2009-05-23 53 views
10

này biên dịch:STL và con trỏ const

int* p1; 
const int* p2; 
p2 = p1; 

này không:

vector<int*> v1; 
vector<const int*> v2; 
v2 = v1; // Error! 
v2 = static_cast<vector<const int*> >(v1); // Error! 

gì là các quy tắc tương đương kiểu cho con trỏ const lồng nhau? Tôi nghĩ rằng chuyển đổi sẽ được ngầm định. Bên cạnh đó, tôi không muốn thực hiện phân bổ điểm khôn ngoan của container STL, trừ khi tôi thực sự phải.

Trả lời

44

Chuyển nhượng trực tiếp là không thể. Như những người khác đã giải thích, sự tương đương không được thiết lập bởi các kiểu con trỏ, mà bởi các kiểu container. Trong trường hợp này, vectơ không muốn chấp nhận một vectơ khác có kiểu phần tử khác, nhưng tương thích.

Không vấn đề thực sự, vì bạn có thể sử dụng chức năng assign thành viên:

v2.assign(v1.begin(), v1.end()); 
+2

Tại sao? Tôi sẽ hiểu được do dự về ngầm chuyển đổi vector để vector , nhưng int * để const int *? Tôi nghĩ const sẽ nhận được sự đối xử đặc biệt trong lĩnh vực này. Bất kỳ ý tưởng tại sao tiêu chuẩn C++ quyết định chống lại nó? –

+0

Có lẽ một cái gì đó để làm với các mẫu được kết hợp chính xác, không phải lúc nào cũng thuận tiện nhất. – user7116

+10

Tôi thấy ví dụ này ở đâu đó: Apple là trái cây, nhưng một túi táo không phải là một túi trái cây. Nó sẽ vi phạm Nguyên tắc thay thế Liskov: bạn có thể đặt một quả cam vào một túi trái cây, nhưng bạn không thể bỏ một quả cam vào một túi táo. Nếu Bag (hoặc, trong trường hợp của bạn, vector ) là bất biến, bạn sẽ không có vấn đề này. –

7

Vấn đề không phải là con trỏ, mà là các loại của hai vectơ. Không có chuyển đổi tiêu chuẩn nào giữa các loại templated như v1 và v2 trong ví dụ của bạn.

Đây có lẽ là dễ dàng hơn để nhìn thấy trong đoạn mã sau:

#include <vector> 
using namespace std; 

int main() { 
    vector <char> cv; 
    vector <int> iv; 
    cv = iv; // error 
} 
20

Chuyển đổi từ int* để const int* được xây dựng vào ngôn ngữ, nhưng vectơ trong số này có không chuyển đổi tự động từ một đến khác.

3

Nó sẽ là hoàn toàn có thể viết phiên bản của riêng bạn vector nơi này là có thể. Nó sẽ giống với loại tiêu chuẩn, nhưng với một phiên bản templated của operator=, một cái gì đó như thế này:

template <class A> 
vector2<T> &operator=(const vector2<A> &other) 
{ 
    assign(other.begin(), other.end()); 
    return *this; 
} 

đâu T là loại yếu tố của cả lớp, trong khi A là bất kỳ loại thể chuyển nhượng để T.

Nó không rõ ràng với tôi tại sao std::vector không có điều này.

4

Trong C++ lớp templated, mỗi instantiation của mẫu là một lớp học hoàn toàn khác nhau - có càng nhiều sự khác biệt giữa vector<int *>vector<const int *> là có giữa vector<int *>vector<string> hoặc bất kỳ hai lớp khác cho rằng vấn đề.

Có thể là Ủy ban có thể thêm vào một nhà điều hành chuyển đổi trên vector-vector<U> như Earwicker gợi ý - và bạn có thể đi trước và cung cấp thực hiện riêng của bạn về một chức năng như:

template <class A, class T> 
vector<T> convert_vector(const vector<A> &other) 
{ 
    vector<T> newVector; 
    newVector.assign(other.begin(), other.end()); 
    return newVector; 
} 

và sử dụng nó như như vậy:

vector<int*> v1; 
vector<const int*> v2; 
v2 = convert_vector<const int*>(v1); 

Thật không may, cho đến khi C++ 0x đi kèm với các nhà thầu di chuyển, điều này sẽ khá kém hiệu quả.

1

Coercion by Member Template thành ngữ là một trong những cách tiếp cận khả thi để giải quyết vấn đề. Về cơ bản, một toán tử gán bản sao của thành viên được thêm vào, cho phép lớp mẫu tham gia vào cùng một kiểu chuyển đổi tiềm ẩn (cưỡng chế), nếu không thì chỉ có thể có trên các tham số kiểu của mẫu lớp.Mặc dù thành ngữ được sử dụng trong STL ở những nơi khác, nó không có sẵn trong std :: vector.

2

nguy hiểm, trừ khi bạn biết các loại là hoàn toàn tương thích:

v2 = reinterpret_cast<std::vector<const int *> & >(v1);

Hầu hết các triển khai STL làm sử dụng một chuyên môn đều vectơ của con trỏ chia sẻ việc thực hiện cơ bản giống nhau. Điều này là do (void *) thường có cùng kích thước với (int *) hoặc bất kỳ kiểu con trỏ nào khác.

2

Điểm quan trọng không được đề cập trong bất kỳ câu trả lời nào trước đây là các chuyên môn về mẫu làm cho việc này không thể thực hiện trên cơ sở toàn ngôn ngữ. Xem xét:

template<class T> 
class Test 
{ 
    T t; 
}; 

template<> 
class Test<const int> 
{ 
    char array[1000]; 
}; 

Như vậy Test<const int> chứa một mảng các ký tự, trong khi Test<int> chứa một int duy nhất.

#include <iostream> 
using namespace std; 

int main() 
{ 
    Test<int> t1; 
    Test<const int> t2; 
    cout << sizeof(t1) << endl; // gives 4 
    cout << sizeof(t2) << endl; // gives 1000 
    return 0; 
} 

Trên thực tế vector<foo *>vector<const foo *> khó có thể khác nhau ở tất cả --- đặc biệt, họ có thể có cùng kích thước. Tuy nhiên, khả năng của chuyên môn mẫu rõ ràng có nghĩa là chúng có thể khác nhau một cách ngoạn mục, do đó sự miễn cưỡng của trình biên dịch cho phép chuyển đổi.

(Câu trả lời này chủ yếu được sao chép từ http://bytes.com/topic/c/answers/449611-cast-vector-foo-vector-const-foo#post1717570)

Các vấn đề liên quan