2016-08-18 23 views
5

Tôi dường như không thể tìm thấy nhiều thông tin về việc liệu trình vòng lặp có giữ lại đối tượng bên dưới mà chúng đang lặp lại hay không.Trình lặp C++ có giữ tham chiếu đến đối tượng bên dưới không?

Nếu tôi tạo trình lặp, thì đối tượng cung cấp nó vượt quá phạm vi, sự hiện diện của trình vòng lặp có ngăn không cho nó bị hủy không?

Dưới đây là một ví dụ rất đơn giản chỉ để minh họa cho kịch bản:

// This class takes a copy of iterators to use them later 
class Data { 
    public: 
    Data(std::vector<int>::iterator start, std::vector<int>::iterator end) 
     : start(start), 
     end(end) 
    {} 

    void show() { 
     // Use this->start and this->end for some purpose 
    } 

    private: 
    std::vector<int>::iterator start; 
    std::vector<int>::iterator end; 
}; 

Data test() { 
    std::vector<int> v{1, 2, 3}; 
    Data d(v.begin(), v.end()); 
    d.show(); // this would be ok 
    return d; 
} 

int main(void) { 
    Data d = test(); 
    d.show(); // What happens here? 
} 

Trong ví dụ này, các đối tượng Data được lưu trữ một bản sao của vòng lặp, mà là tốt cho show() cuộc gọi đầu tiên. Tuy nhiên vào thời điểm cuộc gọi show() thứ hai, đối tượng gốc cung cấp các trình vòng lặp không còn tồn tại nữa.

Các trình vòng lặp có giữ đối tượng xung quanh cho đến khi chúng bị phá hủy hoặc các trình vòng lặp không hợp lệ ngay khi đối tượng ban đầu nằm ngoài phạm vi?

Đây là one reference of many mà không nói những gì xảy ra cách này hay cách khác (hoặc thậm chí cho dù kết quả của việc này là 'undefined').

+7

Bộ lặp được mô phỏng hóa trên con trỏ. Nói chung, nếu một con trỏ không thể làm điều X cấp cao, thì không thể lặp lại. –

+0

Có, trình lặp sẽ bị vô hiệu, kết quả là không xác định. – songyuanyao

+1

Để giải quyết tình huống cụ thể của bạn: phá hủy một thùng chứa sẽ vô hiệu hóa tất cả các trình vòng lặp vào nó. –

Trả lời

5

Bộ lặp thường không sở hữu dữ liệu mà chúng lặp lại, không. Trong thực tế, chúng hiếm khi (nếu có) thậm chí nhận biết của đối tượng sở hữu dữ liệu; các trình vòng lặp vector, ví dụ, thường chỉ là các con trỏ, mà không có kiến ​​thức về bất kỳ vectơ hoặc tuổi thọ của nó. Ngay cả những vòng lặp không được thực hiện như con trỏ (mà là hầu hết trong số họ) có thể được coi là một loại "con trỏ", và đối xử như vậy: họ có thể khá dễ dàng trở nên lúng túng.

Ví dụ của bạn có UB vì bạn sẽ dereference vòng lặp không hợp lệ bên trong show() lần thứ hai.

Nếu vùng chứa của bạn nằm ngoài phạm vi thì tất cả các trình vòng lặp của bạn sẽ bị vô hiệu. Trong thực tế, there are all manner of reasons why an iterator may become invalidated, chẳng hạn như thêm vào một vector khi hoạt động đó dẫn đến việc mở rộng dung lượng.

Có thể tìm thấy lặp rằng làm loại dữ liệu "riêng", thay vì lặp qua một số bộ sưu tập tìm thấy ở nơi khác (chẳng hạn như Boost's counting iterators), nhưng đây là những đặc tính kỳ diệu mà tận dụng lợi thế của C++ cung cấp một chức năng huyền diệu, không phải là thuộc tính vốn có của các trình vòng lặp như được định nghĩa bởi C++.

2

Một iterator là thường chỉ có giá trị càng lâu càng có nguồn gốc của nó container hoặc "chuỗi" đã không bị thay đổi, bởi vì một sự thay đổi có thể gây ra tái phân bổ bộ nhớ và bộ nhớ di chuyển. Vì trình biến đổi thường là tham chiếubộ nhớ trong vùng chứa ban đầu, thay đổi trong vùng chứa đã nói có thể làm mất hiệu lực trình lặp.

Bây giờ, một vùng chứa nằm ngoài phạm vi sẽ được thực hiện hủy. Điều đó rõ ràng sẽ là thay đổi vùng chứa và do đó bất kỳ trình lặp nào cho nó sẽ bị vô hiệu trong quá trình này.

1

Đầu tiên, trình lặp không có giao diện để tham chiếu một đối tượng mà nó lặp lại. Nó chỉ thực hiện ngữ nghĩa của con trỏ, vì vậy bạn có thể nghĩ nó là con trỏ trừu tượng. Tất nhiên, nó thực hiện nội bộ có thể giữ một con trỏ đến đối tượng đó, nhưng nó rất khó trong việc thực hiện trong thế giới thực.

Thứ hai, khi vùng chứa của bạn bị hủy (và khi nó nằm ngoài phạm vi), tất cả các đối tượng trong vùng chứa cũng sẽ bị hủy. Do đó, trình vòng lặp trở nên không hợp lệ sau khi vùng chứa của bạn bị hủy. Sau đó incrementing, decrementing và dereferencing iterator sẽ gây ra hành vi không xác định.

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