2009-05-28 77 views
249

Khi tôi thực hiện việc này:Tại sao tôi không thể tạo vectơ tham chiếu?

std::vector<int> hello; 

Mọi thứ đều hoạt động tốt. Tuy nhiên, khi tôi biến nó thành vectơ tham chiếu thay thế:

std::vector<int &> hello; 

Tôi gặp lỗi khủng khiếp như "lỗi C2528: 'pointer': con trỏ tham chiếu là bất hợp pháp".

Tôi muốn đặt một loạt các tham chiếu đến cấu trúc vào một vec-tơ, để tôi không phải can thiệp vào con trỏ. Tại sao vectơ lại giận dữ về điều này? Là lựa chọn duy nhất của tôi để sử dụng một vector con trỏ thay thế?

+34

bạn có thể sử dụng std :: vector > hello; Xem http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=217 –

Trả lời

11

Đó là một lỗ hổng trong ngôn ngữ C++. Bạn không thể lấy địa chỉ của một tham chiếu, vì cố gắng làm như vậy sẽ dẫn đến địa chỉ của đối tượng được nhắc tới, và do đó bạn không bao giờ có thể lấy một con trỏ tới tham chiếu. std::vector hoạt động với con trỏ đến các phần tử của nó, vì vậy các giá trị được lưu trữ cần phải được chỉ ra. Bạn sẽ phải sử dụng con trỏ để thay thế.

+0

Tôi đoán nó có thể được triển khai bằng bộ đệm trống và vị trí mới. Không phải là điều này sẽ có ý nghĩa nhiều. – peterchen

+46

"Lỗ hổng trong ngôn ngữ" quá mạnh. Đó là do thiết kế. Tôi không nghĩ rằng nó là cần thiết mà vector làm việc với con trỏ đến các yếu tố. Tuy nhiên, yêu cầu yếu tố phải được gán. Tài liệu tham khảo thì không. –

+0

Bạn cũng không thể lấy tham chiếu 'sizeof'. –

26

Do tính chất của chúng, chỉ có thể đặt tham chiếu tại thời điểm chúng được tạo; tức là, hai dòng sau đây có tác dụng rất khác nhau:

int & A = B; // makes A an alias for B 
A = C;   // assigns value of C to B. 

thêm tác, điều này là bất hợp pháp:

int & D;  // must be set to a int variable. 

Tuy nhiên, khi bạn tạo một vector, không có cách nào để gán giá trị cho nó là mặt hàng tại sự sáng tạo. Về cơ bản, bạn chỉ cần tạo ra một loạt các ví dụ cuối cùng.

+6

"khi bạn tạo một vectơ, không có cách nào gán các giá trị cho các mục của nó khi tạo" Tôi không hiểu ý của bạn là gì bởi câu lệnh này. "Các mục của nó lúc sáng tạo" là gì? Tôi có thể tạo một véc tơ trống. Và tôi có thể thêm các mục với .push_back(). Bạn chỉ đang chỉ ra rằng các tham chiếu không được cấu hình mặc định. Nhưng tôi chắc chắn có các vectơ của các lớp không được cấu hình mặc định. – newacct

+1

Ype phần tử của tiêu chuẩn :: vector không bắt buộc phải là cấu hình mặc định. Bạn có thể viết struct A {A (int); riêng tư: A(); }; vector a; tốt thôi - miễn là bạn không sử dụng các phương thức như vậy yêu cầu nó phải được cấu hình mặc định (như v.resize (100) - nhưng thay vào đó bạn sẽ cần phải thực hiện v.resize (100, A (1));) –

+0

Và làm thế nào bạn sẽ viết một push_back() trong trường hợp này? Nó vẫn sẽ sử dụng nhiệm vụ, không phải xây dựng. –

250

Loại thành phần của các vùng chứa như vectơ phải là assignable. Tài liệu tham khảo không thể gán được (bạn chỉ có thể khởi tạo chúng một lần khi chúng được khai báo, và bạn không thể làm cho chúng tham chiếu cái gì khác sau này). Các loại không thể gán khác cũng không được phép làm thành phần của vùng chứa, ví dụ: vector<const int> không được phép.

+1

Bạn đang nói tôi không thể có vec tơ vectơ? (Tôi chắc chắn rằng tôi đã làm điều đó ...) –

+6

Có, một tiêu chuẩn :: vector > là chính xác, std :: vector được gán. –

+14

Thật vậy, đây là lý do "thực tế". Lỗi về T * là không thể của T là U & chỉ là một tác dụng phụ của yêu cầu vi phạm mà T phải được gán. Nếu vector có thể kiểm tra chính xác tham số kiểu, thì có thể nó sẽ nói "vi phạm yêu cầu: T & không thể gán" –

14

boost::ptr_vector<int> sẽ hoạt động.

Chỉnh sửa: là đề xuất sử dụng std::vector< boost::ref<int> >, sẽ không hoạt động vì bạn không thể xây dựng mặc định boost::ref.

+7

Nhưng bạn có thể có một loại véc tơ hoặc không cấu hình mặc định, phải không? Bạn chỉ phải cẩn thận không sử dụng ctor mặc định. của vector – Manuel

+1

@Manuel: Hoặc 'thay đổi kích thước'. –

+5

Hãy cẩn thận, hộp chứa con trỏ của Boost có quyền sở hữu độc quyền của người được chỉ định. [Trích dẫn] (http://www.boost.org/doc/libs/1_57_0/libs/ptr_container/doc/ptr_container.html # motivation): "Khi bạn cần ngữ nghĩa chung, thư viện này không phải là thứ bạn cần". –

2

Như đã đề cập, bạn có thể sẽ sử dụng một vectơ con trỏ thay thế.

Tuy nhiên, bạn có thể muốn cân nhắc sử dụng số ptr_vector thay thế!

+3

Câu trả lời này không khả thi, vì ptr_vector được cho là bộ nhớ. Đó là nó sẽ xóa các con trỏ lúc gỡ bỏ. Vì vậy, nó không phải là có thể sử dụng cho mục đích của mình. –

74

có bạn có thể, hãy tìm std::reference_wrapper, bắt chước một tham chiếu nhưng là chuyển nhượng và cũng có thể được "reseated"

+1

Có cách nào để gọi xung quanh gọi 'get()' trước khi cố truy cập một phương thức của một thể hiện của một lớp trong trình bao bọc này không? Ví dụ. 'reference_wrapper my_ref (...); my_ref.get(). doStuff(); 'không phải là rất tham khảo như thế nào. – timdiels

+3

Không phải là nó có thể cast một cách chính xác đến Type bằng cách trả về tham chiếu? – WorldSEnder

16

Ion Todirel đã đề cập một câu trả lời YES sử dụng std::reference_wrapper. Vì C++ 11, chúng tôi có cơ chế truy xuất đối tượng từ std::vector và xóa tham chiếu bằng cách sử dụng std::remove_reference. Dưới đây là một ví dụ được biên soạn bằng cách sử dụng g++clang với tùy chọn
-std=c++11 và thực thi thành công.

#include <iostream> 
#include <vector> 
#include<functional> 

class MyClass { 
public: 
    void func() { 
     std::cout << "I am func \n"; 
    } 

    MyClass(int y) : x(y) {} 

    int getval() 
    { 
     return x; 
    } 

private: 
     int x; 
}; 

int main() { 
    std::vector<std::reference_wrapper<MyClass>> vec; 

    MyClass obj1(2); 
    MyClass obj2(3); 

    MyClass& obj_ref1 = std::ref(obj1); 
    MyClass& obj_ref2 = obj2; 

    vec.push_back(obj_ref1); 
    vec.push_back(obj_ref2); 

    for (auto obj3 : vec) 
    { 
     std::remove_reference<MyClass&>::type(obj3).func();  
     std::cout << std::remove_reference<MyClass&>::type(obj3).getval() << "\n"; 
    }    
} 
+5

Tôi không thấy giá trị trong 'std :: remove_reference <>' ở đây. Điểm của 'std :: remove_reference <>' là cho phép bạn viết "kiểu T, nhưng không có tham chiếu nếu nó là một". Vì vậy, 'std :: remove_reference :: type' chỉ giống như viết' MyClass'. – alastair

+0

Không có giá trị nào cả - bạn chỉ có thể viết ** 'cho (MyClass obj3: vec) std :: cout << obj3.getval() <<" \ n ";' ** (hoặc 'cho (const MyClass & obj3: vec) 'nếu bạn khai báo' getval() 'const, như bạn nên). –

0

Như các nhận xét khác đề xuất, bạn bị giới hạn sử dụng con trỏ. Nhưng nếu nó giúp, đây là một kỹ thuật để tránh phải đối mặt trực tiếp với con trỏ.

Bạn có thể làm một cái gì đó như sau:

vector<int*> iarray; 
int default_item = 0; // for handling out-of-range exception 

int& get_item_as_ref(unsigned int idx) { 
    // handling out-of-range exception 
    if(idx >= iarray.size()) 
     return default_item; 
    return reinterpret_cast<int&>(*iarray[idx]); 
} 
+0

'reinterpret_cast' không cần thiết – Xeverous

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