Tại sao đối số kiểu bản đồ C ++ yêu cầu một hàm tạo trống khi sử dụng []?


98

Xem thêm danh sách tiêu chuẩn C ++ và các loại cấu trúc mặc định

Không phải là một vấn đề lớn, chỉ là khó chịu vì tôi không muốn lớp học của mình được khởi tạo mà không có các đối số cụ thể.

#include <map>

struct MyClass
{
    MyClass(int t);
};

int main() {
    std::map<int, MyClass> myMap;
    myMap[14] = MyClass(42);
}

Điều này mang lại cho tôi lỗi g ++ sau:

/usr/include/c++/4.3/bits/stl_map.h:419: error: không có hàm phù hợp cho lệnh gọi đến 'MyClass ()'

Điều này biên dịch tốt nếu tôi thêm một hàm tạo mặc định; Tôi chắc chắn rằng nó không phải do cú pháp sai.


Đoạn mã trên biên dịch tốt trên MinGW (g ++ 3.4.5) và MSVC ++ 2008, với điều kiện là một typedef cho MyType được cung cấp và một dấu chấm phẩy được nối vào cuối lớp. Bạn phải làm việc khác (ví dụ: gọi tổng đài [] như bb đã đề cập) - vui lòng đăng mã đầy đủ .
j_random_hacker

À, vâng, bạn nói đúng. Sẽ làm.
Nick Bolton

Vâng, nếu không sử dụng MyMap, bạn sẽ không biết những gì cần được biên dịch cho lớp bản đồ. Nhà cung cấp và phiên bản thư viện stl nào cũng có thể hữu ích.
Greg Domjan,

Câu trả lời:


165

Vấn đề này đi kèm với toán tử []. Trích dẫn từ tài liệu SGI:

data_type& operator[](const key_type& k)- Trả về một tham chiếu đến đối tượng được liên kết với một khóa cụ thể. Nếu bản đồ chưa chứa một đối tượng như vậy, hãy operator[] chèn đối tượng mặc định data_type().

Nếu bạn không có hàm tạo mặc định, bạn có thể sử dụng các hàm insert / find. Ví dụ sau hoạt động tốt:

myMap.insert( std::map< int, MyClass >::value_type ( 1, MyClass(1) ) );
myMap.find( 1 )->second;

11
Câu trả lời tuyệt vời - cũng lưu ý emplacetrong C ++ 11 như một sự thay thế ngắn gọn cho insert.
hào

3
Tại sao lại std::<map>::value_typecó trong insertcuộc gọi?
thomthom

1
Tại sao hàm tạo mặc định cần được người dùng định nghĩa?
schuess

@schuess Tôi không thấy lý do tại sao nó lại như vậy: = defaultsẽ hoạt động tốt.
underscore_d

Điều kiện 'Bản đồ chưa chứa một đối tượng như vậy' sẽ được đánh giá trong thời gian chạy. Tại sao lỗi thời gian biên dịch?
Gaurav Singh

8

Đúng. Giá trị trong vùng chứa STL cần duy trì ngữ nghĩa bản sao. IOW, chúng cần phải hoạt động giống như các kiểu nguyên thủy (ví dụ int), có nghĩa là, trong số những thứ khác, chúng phải có cấu trúc mặc định.

Nếu không có điều này (và các yêu cầu khác), sẽ rất khó thực hiện các thao tác sao chép / di chuyển / hoán đổi / so sánh nội bộ khác nhau trên các cấu trúc dữ liệu mà các vùng chứa STL được triển khai.

Khi tham chiếu đến Tiêu chuẩn C ++, tôi thấy câu trả lời của mình không chính xác. Trên thực tế, cấu trúc mặc định không phải là một yêu cầu :

Từ 20.1.4.1:

Hàm tạo mặc định không bắt buộc. Các chữ ký hàm thành viên lớp vùng chứa nhất định chỉ định hàm tạo mặc định làm đối số mặc định. T () phải là một biểu thức được xác định rõ ...

Vì vậy, nói một cách chính xác, kiểu giá trị của bạn chỉ cần được tạo mặc định nếu bạn tình cờ sử dụng một hàm của vùng chứa sử dụng hàm tạo mặc định trong chữ ký của nó.

Các yêu cầu thực (23.1.3) từ tất cả các giá trị được lưu trữ trong các vùng chứa STL là CopyConstructibleAssignable.

Ngoài ra còn có các yêu cầu cụ thể khác đối với các vùng chứa cụ thể, chẳng hạn như hiện hữu Comparable(ví dụ: đối với các khóa trong bản đồ).


Ngẫu nhiên, các biên dịch sau không có lỗi trên Comeau :

#include <map>

class MyClass
{
public:
    MyClass(int t);
};

int main()
{
    std::map<int, MyClass> myMap;
}

Vì vậy, đây có thể là một vấn đề g ++.


2
Bạn có nghĩ bb có thể liên quan đến toán tử [] không?
Nick Bolton

12
Mã mà có thể biên dịch bởi vì bạn không gọi myMap []
jfritz42

3

Kiểm tra các yêu cầu của kiểu lưu trữ của stl :: map. Nhiều bộ sưu tập stl yêu cầu kiểu được lưu trữ chứa một số thuộc tính cụ thể (hàm tạo mặc định, hàm tạo sao chép, v.v.).

Hàm tạo không có đối số là cần thiết cho stl :: map, bởi vì nó được sử dụng, khi toán tử [] được gọi với khóa, khóa này chưa được bản đồ lưu giữ. Trong trường hợp này, toán tử [] sẽ chèn mục nhập mới bao gồm khóa và giá trị mới được tạo bằng hàm tạo không tham số. Và giá trị mới này sau đó được trả về.


-2

Kiểm tra nếu:

  • Bạn quên dấu ';' sau khi khai báo lớp.
  • MyType nên được khai báo tương ứng.
  • Không có hàm tạo mặc định nào ở đó ...

Tôi nghĩ rằng khai báo bản đồ std :: có vẻ đúng.


Biên dịch tốt nếu tôi thêm một hàm tạo mặc định.
Nick Bolton

-2

Rất có thể vì std :: pair yêu cầu nó. std :: cặp chứa hai giá trị bằng cách sử dụng ngữ nghĩa giá trị, vì vậy bạn cần có thể khởi tạo chúng mà không cần tham số. Vì vậy, mã sử dụng std :: pair ở nhiều nơi khác nhau để trả về các giá trị bản đồ cho người gọi và điều này thường được thực hiện bằng cách khởi tạo một cặp trống và gán các giá trị vào nó trước khi trả về cặp cục bộ.

Bạn có thể giải quyết vấn đề này với con trỏ thông minh bằng cách sử dụng bản đồ <int, smartptr <MyClass>> nhưng điều đó làm tăng chi phí kiểm tra con trỏ rỗng.


2
+0. Cặp <T, U> có thể được sử dụng tốt với các kiểu T và U thiếu các hàm tạo mặc định - điều duy nhất không thể được sử dụng trong trường hợp này là hàm tạo mặc định của riêng cặp <T, U>. Không có sự triển khai chất lượng tốt của bản đồ <K, V> sẽ sử dụng hàm tạo mặc định này vì nó giới hạn những gì K và V có thể có.
j_random_hacker
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.