C++:实现复制构造函数和复制赋值运算符
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4700991/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++ : Implementing copy constructor and copy assignment operator
提问by blitzkriegz
After reading about copy constructors and copy assignment operators in C++, I tried to create a simple example. Though the below snippet apparently works, I am not sure whether I am implementing the copy constructor and copy assignment operator the right way. Could you please point out if there are any mistakes/improvements or a better example to understand the relevant concepts.
在阅读了 C++ 中的复制构造函数和复制赋值运算符之后,我尝试创建一个简单的示例。尽管下面的代码片段显然有效,但我不确定我是否以正确的方式实现了复制构造函数和复制赋值运算符。您能否指出是否有任何错误/改进或更好的示例来理解相关概念。
class Foobase
{
int bInt;
public:
Foobase() {}
Foobase(int b) { bInt = b;}
int GetValue() { return bInt;}
int SetValue(const int& val) { bInt = val; }
};
class Foobar
{
int var;
Foobase *base;
public:
Foobar(){}
Foobar(int v)
{
var = v;
base = new Foobase(v * -1);
}
//Copy constructor
Foobar(const Foobar& foo)
{
var = foo.var;
base = new Foobase(foo.GetBaseValue());
}
//Copy assignemnt operator
Foobar& operator= (const Foobar& other)
{
if (this != &other) // prevent self-assignment
{
var = other.var;
base = new Foobase(other.GetBaseValue());
}
return *this;
}
~Foobar()
{
delete base;
}
void SetValue(int val)
{
var = val;
}
void SetBaseValue(const int& val)
{
base->SetValue(val);
}
int GetBaseValue() const
{
return(base->GetValue());
}
void Print()
{
cout<<"Foobar Value: "<<var<<endl;
cout<<"Foobase Value: "<<base->GetValue()<<endl;
}
};
int main()
{
Foobar f(10);
Foobar g(f); //calls copy constructor
Foobar h = f; //calls copy constructor
Foobar i;
i = f;
f.SetBaseValue(12);
f.SetValue(2);
Foobar j = f = z; //copy constructor for j but assignment operator for f
z.SetBaseValue(777);
z.SetValue(77);
return 1;
}
采纳答案by James McNellis
Your copy assignment operator is implemented incorrectly. The object being assigned to leaks the object its base
points to.
您的复制赋值运算符未正确实现。分配给的对象会泄漏其base
指向的对象。
Your default constructor is also incorrect: it leaves both base
and var
uninitialized, so there is no way to know whether either is valid and in the destructor, when you call delete base;
, Bad Things Happen.
您的默认构造函数也是不正确的:它同时保留base
和var
未初始化,因此无法知道其中一个是否有效并且在析构函数中,当您调用时delete base;
,坏事发生了。
The easiest way to implement the copy constructor and copy assignment operator and to know that you have done so correctly is to use the Copy-and-Swap idiom.
实现复制构造函数和复制赋值运算符并知道您是否正确执行的最简单方法是使用Copy-and-Swap idiom。
回答by wilhelmtell
Only Foobar
needs a custom copy constructor, assignment operator and destructor. Foobase
doesn't need one because the default behaviour the compiler gives is good enough.
只Foobar
需要一个自定义的复制构造函数、赋值运算符和析构函数。Foobase
不需要,因为编译器给出的默认行为已经足够好了。
In the case of Foobar
you have a leak in the assignment operator. You can easily fix it by freeing the object before allocating it, and that should be good enough. But if you ever add a secondpointer member to Foobar
you will see that that's when things get complicated. Now, if you have an exception while allocating the second pointer you need to clean up properly the first pointer you allocated, to avoid corruption or leaks. And things get more complicated than that in a polynomial manner as you add more pointer members.
如果Foobar
您在赋值运算符中有泄漏。您可以通过在分配对象之前释放对象来轻松修复它,这应该足够了。但是,如果您向其中添加第二个指针成员,Foobar
您会发现那是事情变得复杂的时候。现在,如果您在分配第二个指针时遇到异常,您需要正确清理您分配的第一个指针,以避免损坏或泄漏。随着您添加更多指针成员,事情变得比多项式方式更复杂。
Instead, what you want to do is implement the assignment operator in terms of the copy constructor. Then, you should implement the copy-constructor in terms of a non-throwing swap function. Read about the Copy & Swap idiom for details.
相反,您想要做的是根据复制构造函数实现赋值运算符。然后,您应该根据非抛出交换函数来实现复制构造函数。有关详细信息,请阅读复制和交换习语。
Also, the default constructor of Foobar
doesn't default-initialize the members. That's bad, because it's not what the user would expect. The member pointer points at an arbitrary address and the int has an arbitrary value. Now if you use the object the constructor created you are very near Undefined Behaviour Land.
此外, 的默认构造函数Foobar
不会默认初始化成员。这很糟糕,因为这不是用户所期望的。成员指针指向任意地址,int 具有任意值。现在,如果您使用构造函数创建的对象,您将非常接近 Undefined Behavior Land。
回答by Matthieu M.
I have a very simple patch for you:
我有一个非常简单的补丁给你:
class Foobar
{
int var;
std::unique_ptr<FooBase> base;
...
That should get you started.
这应该让你开始。
The bottom line is:
底线是:
- Don't call
delete
in your code (Experts see point 2) - Don't call
delete
in your code (you know better...)
- 不要调用
delete
你的代码(专家见第 2 点) - 不要调用
delete
你的代码(你更清楚......)