2016-08-27 19 views
12

Tôi đang triển khai cơ chế signal/slot (quan sát mẫu, kiểu Qt) của riêng mình để tôi có thể có property thông báo ... nội dung ... đã thay đổi.Các tín hiệu thực hiện (mẫu quan sát): có thể thay đổi hoặc const_cast cần thiết?

Tôi nghĩ C++ 11 cung cấp mọi thứ cần thiết để thực hiện triển khai rất tốt và có tính năng có thể. Các "vấn đề" tôi đang chạy vào là nếu tôi muốn "kết nối" với một tín hiệu của một đối tượng const, tôi cần các chức năng signal::connect được const, nhưng sửa đổi danh sách callbacks/quan sát viên. Có hai cách đơn giản để khắc phục điều này:

  1. const_cast danh sách bên trong connect.
  2. Lập danh sách mutable.

Cả hai dường như với tôi như điều tương tự (và điều này đã được yêu cầu trước đó, ví dụ trong this question), và hoàn toàn tốt đẹp một cách logic, nhưng phong cách đáng ngờ. Do đó câu hỏi. Có cách nào xung quanh việc này hay đây là việc sử dụng thực sự hợp lý của const_cast/mutable?

Một số mã prelimenary như tôi có nó bây giờ:

template<typename... ArgTypes> 
class signal 
{ 
public: 
    template<typename Callable> 
    void connect(Callable&& callback) const 
    { 
    std::lock_guard<std::mutex> lock(slots_mutex); 
    slots.emplace_back(callback); 
    } 

    void emit(ArgTypes... arguments) const 
    { 
    std::lock_guard<std::mutex> lock(slots_mutex); 
    for(auto&& callback : slots) 
    { 
     callback(arguments...); 
    } 
    } 

private: 
    // mutable here allows to connect to a const object's signals 
    mutable std::vector<std::function<void(ArgTypes...)>> slots; 
    std::mutex slots_mutex; 

}; 

Lưu ý tôi đã không kiểm tra mã này; đây chỉ là sự phản ánh trạng thái hiện tại của tôi.

+2

Mã không được kiểm tra ... tsk tsk ... –

+0

@Arnav Tôi đang viết các bài kiểm tra ngay bây giờ, tôi chỉ cần thiết để khắc phục vấn đề thiết kế này: p. – rubenvb

+0

Tôi sợ tôi không hiểu tại sao 'tín hiệu' chính nó nên phơi bày' const' phương pháp. Tại sao không cho phép người dùng 'tín hiệu' quyết định liệu họ muốn nó có thể thay đổi được (hay không)? –

Trả lời

9

mutable thường là lựa chọn tốt hơn cho các trường hợp như vậy.

Tránh (const) đúc bất cứ khi nào bạn có thể, nó dễ bị cho đánh hành vi không xác định, trong khi mutable là đảm bảo được không 1).


mutable thành viên lớp được bảo đảm không đi đến mã phát ra .text phân khúc ví dụ.

2

Có hai cách đơn giản để khắc phục điều này:

  1. const_cast danh sách bên connect.
  2. Lập danh sách mutable.

Trong thực tế có một sự lựa chọn thứ ba (mà là một mục đích chung-xin được khắc phục, có C++ không được cung cấp từ khóa mutable) - bạn có thể di chuyển dữ liệu có liên quan ra khỏi đối tượng cú pháp:

class X 
{ 
    mutable int   i1_; 

    // Data pointed to by i2_ semantically belongs to this object 
    // but doesn't constitute a syntactical part of it so it is not 
    // subject to const-correctness checks by the compiler. 
    std::unique_ptr<int> i2_; 

public: 
    void constFunc() const { 
     i1_ = 123; 
     *i2_ = 456; 
    } 
}; 

Mặc dù có sẵn tùy chọn bổ sung này, tôi vẫn đồng ý với πάντα ῥεῖ 's answer rằng từ khóa mutable là lựa chọn đúng cho các trường hợp như vậy. Nó rõ ràng tài liệu một cách tiêu chuẩn hóa (ví dụ như cho phép được grepped) rằng các hoạt động khái niệm const của lớp này có thể không phải là kỹ thuật không đột biến.Điều này là tốt để biết, ví dụ, khi được quan tâm với an toàn thread của const chức năng của lớp.

0

Tín hiệu :: kết nối không sửa đổi tín hiệu :: khe. Vì vậy, tôi nghĩ rằng điều duy nhất bạn cần làm là thay đổi thiết kế của bạn. Hãy để tín hiệu :: kết nối có thể tắt tiếng và người gọi giữ được tín hiệu con trỏ có thể thay đổi.

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