Liệu toán tử std :: unordered_map [] có khởi tạo không cho khóa không xuất hiện không?


25

Theo cppreference.com, std::map::operator[]đối với giá trị không tồn tại không khởi tạo bằng không.

Tuy nhiên, cùng một trang web không đề cập đến việc khởi tạo bằng không std::unordered_map::operator[], ngoại trừ nó có một ví dụ dựa trên điều này.

Tất nhiên đây chỉ là một trang web tham khảo, không phải là tiêu chuẩn. Vậy, mã dưới đây có ổn hay không?

#include <unordered_map>
int main() {
    std::unordered_map<int, int> map;
    return map[42];     // is this guaranteed to return 0?
}

13
@ Ælex bạn không thể kiểm tra một cách đáng tin cậy nếu một cái gì đó được khởi tạo
idclev 463035818

2
@ Ælex Tôi không thực sự hiểu, làm thế nào bạn có thể không khởi tạo std::optional?
idclev 463035818

2
@ Ælex không có cách nào để kiểm tra xem một đối tượng có được khởi tạo hay không bởi vì bất kỳ thao tác nào trên một đối tượng chưa được khởi tạo khác với kết quả khởi tạo trong Hành vi không xác định. Một std::optionalđối tượng không chứa giá trị chứa vẫn là một đối tượng được khởi tạo.
bolov

2
Đối tượng giá trị được khởi tạo giá trị, không khởi tạo bằng không. Đối với các kiểu vô hướng thì các kiểu này giống nhau, nhưng đối với các kiểu lớp thì chúng khác nhau.
aschepler

@bolov Tôi đã thử kiểm tra nó ngày hôm qua bằng cách sử dụng gnu 17 và std 17, và điều kỳ lạ là tất cả những gì tôi nhận được là không khởi tạo. Tôi nghĩ rằng std::optional has_valuesẽ kiểm tra nó nhưng nó thất bại, vì vậy tôi đoán bạn là chính xác.
Ælex

Câu trả lời:


13

Tùy thuộc vào mức quá tải mà chúng ta đang nói đến, std::unordered_map::operator[]tương đương với [unord.map.elem]

T& operator[](const key_type& k)
{
    return try_­emplace(k).first->second;
}

(quá tải lấy tham chiếu giá trị chỉ di chuyển kvào try_emplacevà giống hệt nhau)

Nếu một phần tử tồn tại dưới khóa ktrong bản đồ, sau đó try_emplacetrả về một trình vòng lặp cho phần tử đó và false. Mặt khác, try_emplacechèn một phần tử mới bên dưới khóa kvà trả về một trình vòng lặp cho điều đó và true [unord.map.modifier] :

template <class... Args>
pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);

Thú vị đối với chúng tôi là trường hợp chưa có yếu tố nào [unord.map.modifier] / 6 :

Mặt khác chèn một đối tượng kiểu được value_­typexây dựng vớipiecewise_­construct, forward_­as_­tuple(k), forward_­as_­tuple(std​::​forward<Args>(args)...)

(quá tải lấy tham chiếu giá trị chỉ di chuyển kvào forward_­as_­tuplevà, một lần nữa, là giống hệt nhau)

value_typepair<const Key, T> [unord.map.overview] / 2 , điều này cho chúng ta biết rằng phần tử bản đồ mới sẽ được xây dựng dưới dạng:

pair<const Key, T>(piecewise_­construct, forward_­as_­tuple(k), forward_­as_­tuple(std​::​forward<Args>(args)...));

argslà trống khi đến từ operator[], nên điều này làm cho giá trị mới của chúng ta được xây dựng như là một thành viên của pairtừ không có đối số [cặp.pair] / 14 là khởi tạo trực tiếp [class.base.init] / 7 của một giá trị loại Tsử dụng ()với tư cách là công cụ khởi tạo để khởi động giá trị khởi tạo [dcl.init] / 17.4 . Giá trị khởi tạo của an intlà khởi tạo bằng 0 [dcl.init] / 8 . Và không khởi tạo một cách inttự nhiên khởi tạo nó intthành 0 [dcl.init] / 6 .

Vì vậy, có, mã của bạn được đảm bảo trả về 0


21

Trên trang bạn liên kết có ghi:

Khi bộ cấp phát mặc định được sử dụng, điều này dẫn đến khóa được sao chép được xây dựng từ khóa và giá trị được ánh xạ được khởi tạo giá trị.

Vì vậy, intgiá trị khởi tạo :

Tác động của việc khởi tạo giá trị là:

[...]

4) nếu không, đối tượng được khởi tạo bằng không

Đây là lý do tại sao kết quả là 0.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.