Vô hiệu hóa trình xây dựng sao chép


172

Tôi có một lớp học:

class SymbolIndexer {
protected:
  SymbolIndexer ( ) { }

public:
  static inline SymbolIndexer & GetUniqueInstance ( ) 
  { 
    static SymbolIndexer uniqueinstance_ ;
    return uniqueinstance_ ; 
  }
};

Tôi nên sửa đổi nó như thế nào để vô hiệu hóa mã như:

SymbolIndexer symbol_indexer_ = SymbolIndexer::GetUniqueInstance ( );

và chỉ cho phép mã như:

SymbolIndexer & ref_symbol_indexer_ = SymbolIndexer::GetUniqueInstance ( );

1
Btw, đây có phải là một singleton với các quy định cho thừa kế (được bảo vệ)?
R. Martinho Fernandes

Tôi có một nghi ngờ trong mã của bạn mỗi khi tạo ra các thể hiện khác nhau, tôi nghĩ GetUniqueInstance () sẽ luôn đưa ra tham chiếu cho cùng một đối tượng.
Pratham Shah

Câu trả lời:


285

Bạn có thể đặt công cụ sao chép riêng tư và không cung cấp triển khai:

private:
    SymbolIndexer(const SymbolIndexer&);

Hoặc trong C ++ 11, rõ ràng cấm nó:

SymbolIndexer(const SymbolIndexer&) = delete;

43
Về deletetừ khóa tôi muốn thêm vào như sau. Thói quen hiện tại của tôi khi thiết kế một lớp mới là ngay deletecả hàm tạo sao chép và toán tử gán. Tôi đã thấy rằng, tùy thuộc vào ngữ cảnh, chúng hầu như không cần thiết và xóa chúng sẽ ngăn ngừa một số trường hợp có hành vi không mong muốn. Nếu một tình huống xảy ra trong đó có thể cần một ctor sao chép, xác định xem nó có thể được thực hiện với ngữ nghĩa di chuyển hay không. Nếu điều này là không mong muốn, hãy cung cấp một triển khai cho cả (!) Trình sao chép và toán tử gán. Cho dù đây là một cách tiếp cận tốt, tôi sẽ để lại cho người đọc.
pauluss86

1
@ pauluss86 Tôi thích cách tiếp cận của bạn nhưng tôi không hoàn toàn cam kết với nó vì tôi nghĩ rằng thời gian theo mô hình này lớn hơn thời gian được lưu bởi các lỗi mà nó ngăn chặn. Tôi chỉ đơn giản là cấm sao chép bất cứ khi nào không chắc chắn.
Tomáš Zato - Phục hồi Monica

@ pauluss86 Về cơ bản, đây là những gì Rust làm: Move-by-default (và const-by-default). Rất hữu ích theo ý kiến ​​của tôi.
Kapichu

33

Nếu bạn không bận tâm đến nhiều kế thừa (rốt cuộc thì nó không tệ lắm), bạn có thể viết lớp đơn giản với hàm tạo sao chép riêng và toán tử gán và thêm lớp con nó:

class NonAssignable {
private:
    NonAssignable(NonAssignable const&);
    NonAssignable& operator=(NonAssignable const&);
public:
    NonAssignable() {}
};

class SymbolIndexer: public Indexer, public NonAssignable {
};

Đối với GCC, thông báo lỗi sau:

test.h: In copy constructor ‘SymbolIndexer::SymbolIndexer(const SymbolIndexer&)’:
test.h: error: ‘NonAssignable::NonAssignable(const NonAssignable&)’ is private

Tôi không chắc chắn cho điều này để làm việc trong mọi trình biên dịch, mặc dù. Có một câu hỏi liên quan , nhưng chưa có câu trả lời.

CẬP NHẬT:

Trong C ++ 11, bạn cũng có thể viết NonAssignablelớp như sau:

class NonAssignable {
public:
    NonAssignable(NonAssignable const&) = delete;
    NonAssignable& operator=(NonAssignable const&) = delete;
    NonAssignable() {}
};

Các deletethành viên ngăn chặn từ khóa khỏi bị mặc định-xây dựng, vì vậy họ không thể tiếp tục sử dụng trong các thành viên mặc định-xây dựng một lớp dẫn xuất của. Cố gắng gán cho lỗi sau trong GCC:

test.cpp: error: use of deleted function
          ‘SymbolIndexer& SymbolIndexer::operator=(const SymbolIndexer&)’
test.cpp: note: ‘SymbolIndexer& SymbolIndexer::operator=(const SymbolIndexer&)’
          is implicitly deleted because the default definition would
          be ill-formed:

CẬP NHẬT:

Boost đã có một lớp chỉ cho cùng một mục đích, tôi đoán nó thậm chí còn được thực hiện theo cách tương tự. Lớp được gọi boost::noncopyablevà có nghĩa là được sử dụng như sau:

#include <boost/core/noncopyable.hpp>

class SymbolIndexer: public Indexer, private boost::noncopyable {
};

Tôi khuyên bạn nên bám sát giải pháp của Boost nếu chính sách dự án của bạn cho phép. Xem thêm một boost::noncopyablecâu hỏi liên quan khác để biết thêm thông tin.


Không nên NonAssignable(const NonAssignable &other);như vậy?
Troyseph

Tôi nghĩ rằng câu hỏi này sẽ nhận được nhiều cách nâng cao hơn nếu nó được cập nhật thành deletecú pháp từ khóa C ++ 11 .
Tomáš Zato - Phục hồi Monica

@ TomášZato: Ý tưởng là giữ bản sao của hàm tạo và toán tử gán, nhưng riêng tư. Nếu bạn delete, họ ngừng hoạt động (Tôi vừa kiểm tra).
firegurafiku

@ TomášZato: Ah, xin lỗi, phương pháp thử nghiệm của tôi hơi sai. Xóa công trình cũng vậy. Sẽ cập nhật câu trả lời trong một phút.
firegurafiku

3
@Troyseph: const Class&Class const&khá giống nhau. Đối với con trỏ, bạn có thể có Class const * constloại thậm chí .
firegurafiku

4

Làm cho SymbolIndexer( const SymbolIndexer& )riêng tư. Nếu bạn đang gán cho một tài liệu tham khảo, bạn không sao chép.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.