在C++中,将对象按值传递给函数时,会通过复制构造函数创建对象的副本。如果类中定义了用户自定义的复制构造函数,那么在初始化函数的临时参数对象时将调用该构造函数。如果没有定义,将使用编译器提供的默认构造函数,该函数执行逐位复制(浅拷贝)。
潜在问题:
示例:
class StringWrapper { char* data; public: StringWrapper(const char* str) { data = new char[strlen(str) + 1]; strcpy(data, str); } // 错误:浅拷贝 StringWrapper(const StringWrapper& other) : data(other.data) {} ~StringWrapper() { delete [] data; } }; void foo(StringWrapper s) { // ... } int main() { StringWrapper s1("hello"); foo(s1); // UB!!! return 0; }
"如果在包含指针的类中这样定义复制构造函数:
MyClass(const MyClass &other) : data(other.data) {}会发生什么?这会导致什么后果?"
正确答案: 这样的复制构造函数将创建一个指向与被复制对象相同内存区域的对象。在销毁这两个对象时,内存将被释放两次(双重释放),这将导致未定义行为。应实现深拷贝:
MyClass(const MyClass &other) { data = new int(*other.data); }
故事
在一个大型服务器项目中,使用了包含"原始"数组的对象容器及标准复制构造函数(浅拷贝)。在按值传递对象时发生了双重释放和应用崩溃,这些问题仅在生产环境中被捕捉到。
故事
在旧的C++图像处理库中,复制构造函数没有复制图形缓冲区,这导致在更改一种图像的同时更改另一种图像,从而导致用户界面中的意外错误。
故事
在一个内部密码管理系统中,从函数返回对象时,临时对象被销毁时数据被清除(浅拷贝),结果是真实对象保存了一个被清零的指针,内存泄漏在安全审计过程中偶然被发现。