2011-01-25 35 views
10

Câu chuyện bắt đầu bằng thứ tôi nghĩ khá đơn giản:Thùng chứa không thay đổi có nội dung có thể thay đổi

Tôi cần thiết kế một lớp sẽ sử dụng một số vùng chứa STL. Tôi cần cấp cho người dùng quyền truy cập lớp vào phiên bản không thể thay đổi của các vùng chứa đó. Tôi không muốn người dùng có thể thay đổi vùng chứa (chúng có thể không phải là push_back() trên danh sách), nhưng tôi muốn người dùng có thể thay đổi các đối tượng chứa (lấy một phần tử với back() và sửa đổi nó) :

class Foo 
{ 
    public: 

    // [...] 

    ImmutableListWithMutableElementsType getImmutableListWithMutableElements(); 

    // [...] 
}; 

// [...] 

myList = foo.getImmutableListWithMutableElements(); 
myElement = myList.back(); 
myElement.change(42); // OK 

// [...] 

// myList.push_back(myOtherElement); // Not possible 

Thoạt nhìn, có vẻ như một container const sẽ làm. Nhưng tất nhiên, bạn chỉ có thể sử dụng trình biến đổi const const trên một thùng chứa const và bạn không thể thay đổi nội dung.

Trong nháy mắt thứ hai, những thứ như container hoặc công cụ vòng lặp chuyên biệt sẽ đến với bạn. Tôi có lẽ sẽ kết thúc với điều đó.

Sau đó, suy nghĩ của tôi là "Ai đó đã làm điều đó rồi!" hoặc "Một giải pháp thanh lịch, chung chung phải tồn tại!" và tôi ở đây hỏi câu hỏi đầu tiên của tôi về SO:

Làm thế nào để bạn thiết kế/chuyển đổi một thùng chứa tiêu chuẩn thành một container không thay đổi với nội dung có thể thay đổi?

Tôi đang làm việc trên đó nhưng tôi có cảm giác như ai đó sẽ chỉ nói "Này, tôi mà mọi thời gian, thật dễ dàng, nhìn kìa!", Vì vậy tôi hỏi ...

Cảm ơn bạn cho bất kỳ gợi ý, gợi ý hoặc cách chung chung tuyệt vời để làm điều đó :)


EDIT:

Sau khi một số thí nghiệm, tôi đã kết thúc với container tiêu chuẩn có thể xử lý một số gợi ý thông minh được trang trí đặc biệt. Nó gần với câu trả lời của Nikolai.

Ý tưởng về một container không thay đổi của các yếu tố có thể thay đổi không phải là một khái niệm giết người, xem các ghi chú thú vị trong câu trả lời của Oli.

Ý tưởng về trình lặp cụ thể là đúng, nhưng có vẻ như không thực tế vì tôi cần phải thích ứng với bất kỳ loại vùng chứa nào.

Cảm ơn tất cả vì sự giúp đỡ của bạn.

Trả lời

5

Tùy chọn đơn giản nhất có thể là một container STL tiêu chuẩn của con trỏ, vì const -ness không được truyền cho các đối tượng thực tế. Một vấn đề với điều này là STL không dọn sạch bất kỳ bộ nhớ heap nào mà bạn đã cấp phát. Để biết điều đó hãy xem Boost Pointer Container Library hoặc smart pointers.

+0

Có, nhưng để có được một container bất biến, tôi phải trả lại một container const, và sau đó tôi sẽ nhận được các yếu tố const từ nó, không? Bạn đề nghị sử dụng const_cast? Tất nhiên nó là một khả năng, nhưng nó sẽ là một nỗi đau để sử dụng ... hoặc làm tôi bỏ lỡ một cái gì đó? – neuro

+0

Các con trỏ trong thùng chứa 'const' sẽ là' const', nhưng không phải là các đối tượng mà chúng trỏ đến. –

+0

vâng, bạn có quyền tất nhiên. Điều duy nhất là nó không phải là chung chung như tôi nghĩ rằng nó có thể được. Là một phần của khuôn khổ, tôi muốn cung cấp khả năng cho các nhà phát triển khuôn khổ sử dụng bất kỳ loại vùng chứa nào. Nhưng sử dụng container con trỏ hoặc container con trỏ thông minh nên làm công việc ... – neuro

5

Thay vì cung cấp cho người dùng toàn bộ vùng chứa, bạn có thể chỉ cung cấp cho họ các trình biến đổi không const để bắt đầu và kết thúc không? Đó là cách STL.

+1

Tính năng này hoạt động, tùy thuộc vào định nghĩa của một người là "sửa đổi vùng chứa". Có 'std :: remove' được tính là sửa đổi vùng chứa không? (Tôi nghĩ như vậy, nhưng có lẽ OP là okay với điều đó.) –

+0

có, nhưng như James nói, với một tiêu chuẩn không const iterator, người dùng có thể sửa đổi các container. Trong mọi trường hợp, tôi phải chuyên container hoặc iterator. Tôi cố gắng tưởng tượng một số giải pháp mà có thể "trang trí" container/iterator của tôi phải viết ít mã :) Nhưng bạn có quyền nói rằng đó là cách STL. Một trình vòng lặp chuyên ngành có thể sẽ thực hiện công việc. – neuro

+0

@James, @neuro: Sẽ công bằng khi nói rằng 'std :: remove' vv không thực sự sửa đổi vùng chứa, mỗi lần. Họ chỉ trao đổi nội dung của các yếu tố khác nhau, đó là một cái gì đó người dùng có thể làm ngay cả khi 'std :: remove' không được phép? –

1

Các giải pháp đau đớn:

/* YOU HAVE NOT SEEN THIS */ 
struct mutable_int { 
    mutable_int(int v = 0) : v(v) { } 
    operator int(void) const { return v; } 
    mutable_int const &operator=(int nv) const { v = nv; return *this; } 

    mutable int v; 
}; 

Xin lỗi tôi trong khi tôi phải trừng phạt bản thân mình để chuộc lỗi cho những tội lỗi của tôi.

+0

Err, đó có lẽ là quá thông minh cho tôi :) các nỗ lực anyway;) – neuro

+0

Cảm ơn một lần nữa và may mắn với hình phạt của bạn;) – neuro

+0

Xin chào, tôi đến từ tương lai và tôi đang cố gắng tìm hiểu C++. Bất cứ ai có thể vui lòng giải thích những gì đang xảy ra ở đây ...? : | –

3

Bạn cần trình theo dõi cấu trúc dữ liệu tùy chỉnh, trình bao bọc xung quanh danh sách riêng tư của bạn.

template<typename T> 
class inmutable_list_it { 
public: 
    inmutable_list_it(std::list<T>* real_list) : real_list_(real_list) {} 

    T first() { return *(real_list_->begin()); } 

    // Reset Iteration 
    void reset() { it_ = real_list_->begin(); } 

    // Returns current item 
    T current() { return *it_; } 

    // Returns true if the iterator has a next element. 
    bool hasNext(); 

private: 
    std::list<T>* real_list_; 
    std::list<T>::iterator it_; 
}; 
+0

Vâng, tôi đã nghĩ về một cái gì đó như thế. Điều làm phiền tôi là tôi cần mã hóa phiên bản chuyên biệt cho bất kỳ loại container nào tôi muốn quản lý ... Tôi sẽ thử phiên bản chung của những gì bạn đề xuất, nếu kỹ năng mẫu kém phù hợp với thử thách :) Cảm ơn sự giúp đỡ của bạn! – neuro

+0

cảm ơn cho ý tưởng của bạn, nó nhắc tôi về một số java iterator bằng cách :) – neuro

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