为何私有拷贝构造/赋值运算符的单例类仍可复制对象?
关于单例类中拷贝构造与赋值运算符未触发的疑惑
我创建了如下单例类,并将拷贝构造函数和赋值运算符声明为私有。当尝试调用拷贝构造函数或赋值运算符时,并未触发这些函数(可能因静态对象创建方式)。我的问题是:为何单例设计模式看似允许从已创建对象复制新对象或赋值新对象(违反单例单一实例的基本要求),即便这些函数已被声明为私有?
详情请参考以下代码:
#include <iostream> #include "conio.h" class singleton { static singleton *s; int i; singleton() { }; singleton(int x):i(x) { std::cout<<"\n Calling one argument constructor"; }; singleton(const singleton&) { std::cout<<"\n Private copy constructor"; } singleton &operator=(singleton&) { std::cout<<"\n Private Assignment Operator"; } public: static singleton *getInstance() { if(!s) { std::cout<<"\n New Object Created\n "; s=new singleton(); return s; } else { std::cout<<"\n Using Old Object \n "; return s; } } int getValue() { std::cout<<"i = "<<i<<"\n"; return i; } int setValue(int n) { i=n; } }; singleton* singleton::s=0; int main() { // Creating first object singleton *s1= singleton::getInstance(); s1->getValue(); singleton *s4=s1; // 看似调用拷贝构造,但实际未触发 singleton *s5; s5=s1; // 看似调用赋值运算符,但实际未触发 //Creating second object singleton *s2=singleton::getInstance(); s2->setValue(32); s2->getValue(); //Creating third object singleton *s3=singleton::getInstance(); s3->setValue(42); s3->getValue(); getch(); return 0; }
我是否遗漏了什么,或是我的理解存在错误?
解答
别担心,你其实没写错单例的核心逻辑,问题出在你混淆了指针操作和对象操作的区别:
你代码里的
s4 = s1和s5 = s1是指针赋值,不是对象拷贝/赋值
这些操作只是让新的指针变量指向已经存在的单例实例,根本没有创建任何新的对象。换句话说,s1、s4、s5都是指向同一个内存地址的指针,它们操作的是同一个单例对象,完全符合单例“唯一实例”的要求。私有拷贝构造和赋值运算符的作用是阻止对象层面的复制
如果你真的尝试创建新的对象实例(而不是新指针),比如写下面的代码:// 尝试用拷贝构造创建新对象——编译会报错,因为拷贝构造是私有 singleton s(*s1); // 尝试对象赋值——同样编译报错 singleton s; s = *s1;这时候编译器会直接报错,提示你无法访问私有成员,这才是你声明私有拷贝构造和赋值运算符的真正作用:彻底阻止创建新的单例对象实例。
你的单例实现本身是有效的
从main函数的输出可以看到,getInstance()只在第一次调用时创建了新对象,后续调用都返回了旧对象,说明单例的核心逻辑是正常工作的。那些指针赋值操作并没有破坏单例的唯一性。
总结一下:你没有遗漏任何关键逻辑,只是误解了指针操作和对象操作的差异——你的单例类已经通过私有拷贝构造和赋值运算符正确阻止了对象复制,当前代码里的指针操作完全符合单例设计的预期。
内容的提问来源于stack exchange,提问作者HumbleSwagger
相关产品推荐
相关产品推荐

