2012-01-29 130 views
11

传递从我明白我能为“禁用”的复制和定义私人拷贝构造函数和赋值操作符分配给我的对象:如果不允许转让和价值

class MyClass 
{ 
private: 
    MyClass(const MyClass& srcMyClass); 
    MyClass& operator=(const MyClass& srcMyClass); 
} 

但是,什么是这种用法?
它被认为是一种不好的做法?

我将不胜感激,如果你能描述的情况,其中我们有理由/为“禁用”分配很有用,在这种方式拷贝构造函数。

+1

一个单就是一个例子。 – 2012-01-29 20:09:15

回答

11

当您的对象无法被复制时,它很有用。这绝对不是坏习惯。

举例来说,如果你有一个代表网络连接的一类,它是没有意义的复制对象。如果你有一个班级代表多人游戏中的一名玩家,那么另一次你可能想要一个班级是不可复制的。这两个类都代表在现实世界中无法复制的东西,或者复制(人,连接)无意义的东西。

另外,如果你想实现一个Singleton,它使物体不可复制的标准程序。

+0

谢谢,这很有道理。那么赋值运算符呢? – LihO 2012-01-29 20:23:09

+3

@LihO一般来说,如果你禁用一个你禁用其他。如果你不禁用赋值操作符,你可以这样做:'MyClass a,b; a = b;'如果你不禁用拷贝构造函数,你可以执行'MyClass b; MyClass a(b);'所以如果你不禁用它们,你可以避开另一个被禁用的。 – 2012-01-29 20:25:49

+0

是的,现在我明白了。 – LihO 2012-01-29 20:27:08

0

当你试图实现一个Singleton模式是完全可以接受的使用私有的构造函数,因为它的意思内本身和其他地方只实例化。 一旦被调用,构造函数就不能被撤销。所以构造函数只有在检查单例条件满足后才会被调用。

2

这是一个很常见的做法。有很多复制不合适的例子。

比方说,你的对象代表一个打开的服务器端套接字(即传入网络连接);制作该对象副本的语义是什么?

5

一般来说,管理资源应该是没有,可复制或有专门的拷贝语义的任何类。反过来也是如此:任何不可复制或需要特殊复制语义的类都是管理资源。在实践中,C++语言中的“管理资源”意味着负责内存中的某些空间,或者连接到网络或数据库,或者文件句柄或撤销事务等等。

资源管理捕获了很多例子。这些职责是采取前缀操作,后缀操作以及可能的一些操作。例如,内存管理涉及获取我们将要管理的内存地址的句柄,可能与该内存混乱,并最终释放句柄(因为如果你喜欢某事,就让它免费)。

template<typename T> 
struct memory { 
    memory(T const& val = T()) : p(new T(val)) { } 
    ~memory() { delete p } 
    T& operator*() const { return *p; } 
private: 
    T* p; 
}; 

// ... 
{ 
    memory<int> m0; 
    *m0 = 3; 
    std::cout << *m0 << '\n'; 
} 

memory类几乎是正确的:它会自动获取底层的内存空间,并自动将其释放,即使异常传播一段时间后,它收购了其资源。但考虑这样的场景:

{ 
    memory<double> m1(3.14); 
    memory<double> m2(m1); // m2.p == m1.p (do you hear the bomb ticking?) 
} 

因为我们没有为memory提供专门的复制语义中,编译器提供了它自己的拷贝构造函数和拷贝赋值。这些做错误事情:m2 = m1意味着m2.p = m1.p,使这两个指针指向相同的地址。这是错误的,因为当m2超出范围时,它将其资源释放为一个好的责任对象,当m1超出范围时,它也释放其资源,同一资源m2已经释放,完成双重删除 - 臭名昭着未定义的行为场景。而且,在C++中,创建对象的副本是非常容易的,甚至不会注意到:函数根据值取其参数,按值返回它的参数,或者通过引用取其参数,然后调用另一个函数,该函数本身需要(或返回)参数值...更容易假设事情试图得到复制。

这一切都是说,当一个班级的理由是管理资源时,你应该立即知道你需要处理复制。你应该决定

  • 你支持复制,而你决定的意思复制:资源的安全共享,进行底层资源的深层副本所以没有共享任何或这两种方法在copy-on-write合并或懒惰的副本。无论您选择哪种路径,您都需要提供专门的复制构造函数复制赋值运算符。
  • 或者您不支持任何形式的资源复制,在这种情况下您将禁用复制构造函数和复制赋值运算符。

我会走到目前为止,并说资源管理是唯一的情况下,您禁用复制或提供专门的复制语义。这仅仅是The Rule of Three的另一个角度。

0

当你被允许创建对象的实例只有在像单身人士的情况下检查你需要私有构造函数。当调用构造函数时,将调用对象实例,然后检查是否还有其他实例没有意义。所以我们所做的就是从main和inside中调用一个类的成员函数,该成员函数检查另一个实例是否已经存在于内存中。如果不是构造函数被调用。别的中止。 检查单体类或其他受保护的类,其中对象的数据必须保持安全,不应该被允许复制。

也检查:Singleton Class in C++