C++使用指针复制构造函数
C++ copy constructor with pointers
我理解需要深度复制指针(在您想要对象的完整副本的情况下),我的困惑来自以下内容(完全编造的示例)。
#include "stdafx.h"
#include <string>
class a
{
public:
a::a(std::string _sz) :
m_sz(_sz)
,m_piRandom(new int)
{
*m_piRandom = 1;
};
~a()
{
delete m_piRandom;
m_piRandom = NULL;
};
a::a(const a &toCopy)
{
operator=(toCopy);
}
a& a::operator=(const a &toAssign)
{
if (this != &toAssign)
{
m_sz = toAssign.m_sz;
if (m_piRandom)
{
// Need to free this memory!
delete m_piRandom;
m_piRandom = NULL;
}
m_piRandom = new int(*toAssign.m_piRandom);
}
return *this;
}
void SetInt(int i)
{
if (!m_piRandom)
{
m_piRandom = new int;
}
*m_piRandom = i;
}
private:
std::string m_sz;
int* m_piRandom;
};
int _tmain(int argc, _TCHAR* argv[])
{
a Orig = a("Original");
a New = a("New");
New.SetInt(9);
New = Orig;
return 0;
}
现在在我的示例中,我想测试一个场景,其中我有一个对象分配了一些内存,在本例中:
a New = a("New");
New.SetInt(9); // This new's the memory
分配内存,然后当我们说:New = Orig;
我预计内存泄漏,因为如果我盲目地新m_piRandom = new int(*toAssign.m_piRandom);
,我会失去它以前指向的内存。
所以我决定在赋值运算符中放入以下内容:
if (m_piRandom)
{
// Need to free this memory!
delete m_piRandom;
m_piRandom = NULL;
}
当调用以下内容(第一行! a Orig = a("Original");
因为它调用复制构造函数(我调用赋值运算符以减少重复),并且指针m_piRandom
设置为 0xcccccccc。不为空。因此,它会尝试删除从未分配的内存。我希望它在到达New = Orig;
时能够工作,因为它会在分配副本之前先删除它。任何人都可以对此有所了解,我想我最大的担忧是m_piRandom不是 NULL,我还尝试为 a 定义一个默认构造函数,默认情况下 NULL 指针,但这没有帮助。为完全人为的代码道歉..
谢谢
你的第一个错误是你根据赋值运算符实现了复制构造函数。复制构造函数基于其他对象引入新对象,而赋值运算符清除并更改已创建对象的位。
因此,您的正确复制构造函数将是:-
a::a(const a &toCopy) : m_sz(toCopy.m_sz), m_piRandom(new int)
{
*m_piRandom = toCopy.m_piRandom;
}
实现此操作后,您可以简化赋值运算符:
a& a::operator=(const a &toAssign)
{
if (this != &toAssign)
{
m_sz = toAssign.m_sz;
if (m_piRandom) //<<<<< No need to check this as it should always be
{ //<<<<< initialized by constructors.
delete m_piRandom;
m_piRandom = NULL;
}
m_piRandom = new int(*toAssign.m_piRandom);
}
return *this;
}
删除这些冗余后,分配运算符如下所示
a& a::operator=(const a &toAssign)
{
if (this != &toAssign)
{
m_sz = toAssign.m_sz;
m_piRandom = new int(*toAssign.m_piRandom);
}
return *this;
}
发生此错误是因为复制构造函数未初始化m_piRandom
。这意味着变量将(很可能)被垃圾填充(初始化对象时内存位置的任何内容)。
调用顺序如下:
a::a() [doesn not initialize m_piRandom] -> a::operator= -> delete m_piRandom.
要修复:
a::a(const a &toCopy)
: m_piRandom{ nullptr } // <---- add this
{
operator=(toCopy);
}
编辑:您可以使用复制和交换习惯用法大幅改进赋值运算符。
代码的问题在于复制构造函数不初始化 int 指针 membrer,但赋值运算符为其假定正确的值。因此,只需在调用赋值运算符之前在复制构造函数中将 int 指针初始化为 0。
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 当从函数参数中的临时值调用复制构造函数时
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- 复制构造函数、赋值运算符C++
- std::ofstream 作为类成员删除复制构造函数?
- 复制构造函数C++无法正确复制指针
- 关于复制构造函数的一个棘手问题
- 为什么调用复制构造函数而不是移动构造函数?
- 填充上编译器生成的复制构造函数之间的不一致
- C++ 对象指针数组的复制构造函数
- C++ 基本 CTOR 说明 - 为什么不调用赋值/复制构造函数
- 防止在复制构造函数中隐式调用基构造函数
- 为用户定义的类正确调用复制构造函数/赋值运算符
- 具有已删除移动和复制构造函数的类的就地构造
- 复制构造函数隐式转换问题
- 复制构造函数中的递归调用