2013-01-06 17 views
23

Tôi đã có một lớp học với một biến thành viên nguyên tử:C++ 11: viết hàm khởi tạo bằng nguyên tử <bool> nguyên tử?

struct Foo 
{ 
    std::atomic<bool> bar; 
    /* ... lots of other stuff, not relevant here ... */ 
    Foo() 
    : bar(false) 
    {} 

    /* Trivial implementation fails in gcc 4.7 with: 
    * error: use of deleted function ‘std::atomic<bool>::atomic(const td::atomic<bool>&)’ 
    */ 
    Foo(Foo&& other) 
    : bar(other.bar) 
    {} 
}; 

Foo f; 
Foo f2(std::move(f)); // use the move 

Làm thế nào nên di chuyển constructor cái nhìn như thế nào?

Gcc 4,7 không thích bất kỳ nỗ lực của tôi (như thêm std::move() quanh other.bar) và lưới là đáng ngạc nhiên yên tĩnh ở đây ...

Trả lời

14

Kể từ khi bạn đang di chuyển other, không ai khác sẽ truy cập vào nó. Vì vậy, đọc từ bar của nó là an toàn, thời tiết nó nguyên tử hay không.

atomic<T> chỉ có hai hàm tạo, một là mặc định (), số còn lại là (T). Vì vậy, mã của bạn trông giống như nó nên biên dịch. Nếu không, điều gì sẽ xảy ra nếu bạn static_cast other.bar đến T, thực thi hàm tạo (T) để sử dụng?

: bar(static_cast<bool>(other.bar))

hoặc tương đương với, và có lẽ ít xấu xí:

: bar(other.bar.load())

+1

Cảm ơn, 'cái bar (other.bar.load()) 'là giải pháp đúng đó là biên dịch bây giờ! – Chris

+7

_So, mã của bạn trông giống như nó cần biên dịch._ Không, 'nguyên tử 'có một hàm tạo bản sao đã xóa và độ phân giải quá tải phát hiện ra rằng không phải hàm tạo' nguyên tử (T) '. Các diễn viên hoặc tải là cần thiết. –

+0

@JonathanKhi bạn nói đúng, tôi nghĩ trình biên dịch sẽ tiếp tục với hàm tạo tiếp theo có thể '(T)' khi nó biết hàm tạo bản sao bị xóa và có một toán tử ''. Có phải lý do cho điều này là hàm tạo nguyên tử cho '(T)' là 'constexpr' làm cho nó hoạt động tương tự như các hàm tạo' tường minh' trong các chuyển đổi ngầm định đó hay không (hoặc trong trường hợp này là 'constexpr')? –

22

std::atomic không copyable hoặc di chuyển vì its copy constructor is deleted và không có constructor di chuyển được xác định. Bạn phải tải một cách rõ ràng giá trị khác và sử dụng nó để xây dựng giá trị mới, vì nó được chỉ ra trong câu trả lời của gustaf.

Tại sao std::atomic không thể di chuyển? Vì nó là một nguyên thủy đồng bộ, tất cả các luồng phải đồng bộ hóa trên cùng một dữ liệu (tức là, cùng một địa chỉ). Khi bạn sao chép (hoặc di chuyển) một giá trị nguyên tử, bạn phải sử dụng một số giao thức truyền thông. Nó có thể đơn giản, như trong ví dụ của bạn (chỉ cần tải nó và sử dụng nó để khởi tạo nguyên tử mới) nhưng, nói chung, tôi nghĩ đó là một quyết định thiết kế tốt bởi C++ 11 để buộc bạn phải suy nghĩ về nó. Nếu không, nó có thể dẫn đến mã có vẻ tốt, nhưng có một số vấn đề đồng bộ hóa subtile.

+1

Tôi đang cố gắng tìm ra một tình huống thực sự có vấn đề khi có một nguyên tử tự động di chuyển khi bạn có nhiều chuỗi. Thủ công buộc phải di chuyển với std :: move() là một việc khác. Dù bằng cách nào, tôi muốn một ví dụ để cho thấy nơi di chuyển một nguyên tử sẽ là vấn đề. Bạn có thể di chuyển bất kỳ vùng chứa 'std' nào khác và bạn dự kiến ​​sẽ xử lý đồng bộ hóa. –

+1

Tôi cũng muốn biết nếu nó sẽ là một ý tưởng tồi nếu 'atomic' sẽ có một constructor di chuyển mà sẽ phải được kích hoạt bằng cách gọi một cách rõ ràng' std :: move() '- nó sẽ cho tôi một giao diện Tôi đã mong đợi. Nhưng tôi quá xa với việc nuôi ong một chuyên gia C++ để phán xét liệu quyết định đó có tiêu chuẩn hay là sai lầm ... – Chris

+1

Không có cách nào cho nhà xây dựng di chuyển quyết định liệu rvalue có được từ một 'std rõ ràng hay không :: move' hoặc là một giá trị ngầm định (ví dụ, giá trị trả về của hàm). Tôi cũng không có chuyên gia về các quyết định thiết kế, nhưng tôi nghĩ một tài nguyên được tính tham chiếu là một ví dụ trong đó nhà xây dựng di chuyển có thể dẫn đến các vấn đề. Tôi sẽ chỉnh sửa câu trả lời của mình và bao gồm ví dụ mà tôi đã lưu ý khi tôi viết về "vấn đề đồng bộ hóa". –

1

Mẫu instantiation của atomic<bool> về cơ bản trông như thế này:

struct atomic<bool> 
{ 
    atomic<bool>(bool); 
    atomic<bool>(const atomic<bool>&) = delete; 
    operator bool() const; 
} 

Vì vậy, khi bạn cố gắng để sao chép nó:

atomic<bool> a = ...; 
atomic<bool> b(a); 

Các nhà xây dựng bản sao xóa được chọn và gây ra một lỗi biên dịch.

Bạn cần phải đúc một cách rõ ràng đến bool phải đi qua operator bool() --> atomic<bool>(bool) ...

atomic<bool> a = ...; 
atomic<bool> b(bool(a)); 
+1

Không an toàn hơn khi sử dụng static_cast (đề cập đến dòng mã cuối cùng trong giải pháp của bạn)? –