Please write a list of tasks that a copy constructor and assignment operator need to do in C++ to keep exception safety, avoid memory leaks etc.
请编写复制构造函数和赋值运算符在C ++中需要执行的任务列表,以保证异常安全,避免内存泄漏等。
4 个解决方案
#1
15
First be sure you really need to support copy. Most of the time it is not the case, and thus disabling both is the way to go.
首先要确保你真的需要支持副本。大部分时间情况并非如此,因此禁用两者是可行的方法。
Sometimes, you'll still need to provide duplication on a class from a polymorphic hierarchy, in that case: disable the assignment operator, write a (protected?) copy constructor, and provide a virtual clone() function.
有时,您仍然需要在多态层次结构中为类提供重复,在这种情况下:禁用赋值运算符,编写(受保护的?)复制构造函数,并提供虚拟clone()函数。
Otherwise, in the case you are writing a value class, you're back into the land of the Orthogonal Canonical Form of Coplien. If you have a member that can't be trivially copied, you'll need to provide a copy-constructor, a destructor, an assignment-operator and a default constructor. This rule can be refined, see for instance: The Law of The Big Two
否则,在你写一个价值类的情况下,你又回到了Coplien正交规范形式的土地上。如果你有一个不能轻易复制的成员,你需要提供一个拷贝构造函数,一个析构函数,一个赋值运算符和一个默认构造函数。这条规则可以改进,例如:“大二法则”
I'd also recommend to have a look at C++ FAQ regarding assignment operators, and at the copy-and-swap idiom and at GOTW.
我还建议看一下有关赋值运算符的C ++ FAQ,以及复制和交换习惯用语以及GOTW。
#2
4
The compiler generated versions work in most situations.
编译器生成的版本适用于大多数情况。
You need to think a bit harder about the problem when your object contains a RAW pointer (an argument for not having RAW pointers). So you have a RAW pointer, the second question is do you own the pointer (is it being deleted by you)? If so then you will need to apply the rule of 4.
当对象包含RAW指针(没有RAW指针的参数)时,您需要更加思考问题。所以你有一个RAW指针,第二个问题是你拥有指针(它是否被你删除)?如果是这样,那么您将需要应用4的规则。
Owning more than 1 RAW pointer becomes increasingly hard to do correctly (The increase in complexity is not linear either [but that is observational and I have no real stats to back that statement up]). So if you have more than 1 RAW pointer think about wrapping each in its own class (some form of smart pointer).
拥有超过1个RAW指针变得越来越难以正确执行(复杂性的增加也不是线性的[但这是观察性的,我没有真正的统计数据来支持该声明])。因此,如果你有超过1个RAW指针考虑将它们包装在它自己的类中(某种形式的智能指针)。
Rule of 4: If an object is the owner of a RAW pointer then you need to define the following 4 members to make sure you handle the memory management correctly:
规则4:如果对象是RAW指针的所有者,那么您需要定义以下4个成员以确保正确处理内存管理:
- Constructor
- Copy Constructor
- Assignment Operator
- Destructor
How you define these will depend on the situations. But things to watch out for:
您如何定义这些将取决于具体情况。但要注意的事项:
- Default Construction: Set pointer to NULL
- Copy Constructor: Use the Copy and Swap ideum to provide to the "Strong Exception Guarantee"
- Assignment operator: Check for assignment to self
- Destructor: Guard against exceptions propagating out of the destructor.
默认构造:将指针设置为NULL
复制构造函数:使用复制和交换标识提供“强异常保证”
分配操作员:检查分配给自己
析构函数:防止从析构函数中传播的异常。
#3
1
try to read this.
试着读一下。
http://www.icu-project.org/docs/papers/cpp_report/the_anatomy_of_the_assignment_operator.html
is a very good analysis of Assignment operator
是一个非常好的分配运算符的分析
#4
-2
I have no idea about exception safely here but I go this way. Let's imagine it's a templated array wrapper. Hope it helps :)
我在这里安全地不知道异常,但我这样做了。让我们想象一下它是一个模板化的数组包装器。希望能帮助到你 :)
Array(const Array& rhs)
{
mData = NULL;
mSize = rhs.size();
*this = rhs;
}
Array& operator=(const Array& rhs)
{
if(this == &rhs)
{
return *this;
}
int len = rhs.size();
delete[] mData;
mData = new T[len];
for(int i = 0; i < len; ++i)
{
mData[i] = rhs[i];
}
mSize = len;
return *this;
}
#1
15
First be sure you really need to support copy. Most of the time it is not the case, and thus disabling both is the way to go.
首先要确保你真的需要支持副本。大部分时间情况并非如此,因此禁用两者是可行的方法。
Sometimes, you'll still need to provide duplication on a class from a polymorphic hierarchy, in that case: disable the assignment operator, write a (protected?) copy constructor, and provide a virtual clone() function.
有时,您仍然需要在多态层次结构中为类提供重复,在这种情况下:禁用赋值运算符,编写(受保护的?)复制构造函数,并提供虚拟clone()函数。
Otherwise, in the case you are writing a value class, you're back into the land of the Orthogonal Canonical Form of Coplien. If you have a member that can't be trivially copied, you'll need to provide a copy-constructor, a destructor, an assignment-operator and a default constructor. This rule can be refined, see for instance: The Law of The Big Two
否则,在你写一个价值类的情况下,你又回到了Coplien正交规范形式的土地上。如果你有一个不能轻易复制的成员,你需要提供一个拷贝构造函数,一个析构函数,一个赋值运算符和一个默认构造函数。这条规则可以改进,例如:“大二法则”
I'd also recommend to have a look at C++ FAQ regarding assignment operators, and at the copy-and-swap idiom and at GOTW.
我还建议看一下有关赋值运算符的C ++ FAQ,以及复制和交换习惯用语以及GOTW。
#2
4
The compiler generated versions work in most situations.
编译器生成的版本适用于大多数情况。
You need to think a bit harder about the problem when your object contains a RAW pointer (an argument for not having RAW pointers). So you have a RAW pointer, the second question is do you own the pointer (is it being deleted by you)? If so then you will need to apply the rule of 4.
当对象包含RAW指针(没有RAW指针的参数)时,您需要更加思考问题。所以你有一个RAW指针,第二个问题是你拥有指针(它是否被你删除)?如果是这样,那么您将需要应用4的规则。
Owning more than 1 RAW pointer becomes increasingly hard to do correctly (The increase in complexity is not linear either [but that is observational and I have no real stats to back that statement up]). So if you have more than 1 RAW pointer think about wrapping each in its own class (some form of smart pointer).
拥有超过1个RAW指针变得越来越难以正确执行(复杂性的增加也不是线性的[但这是观察性的,我没有真正的统计数据来支持该声明])。因此,如果你有超过1个RAW指针考虑将它们包装在它自己的类中(某种形式的智能指针)。
Rule of 4: If an object is the owner of a RAW pointer then you need to define the following 4 members to make sure you handle the memory management correctly:
规则4:如果对象是RAW指针的所有者,那么您需要定义以下4个成员以确保正确处理内存管理:
- Constructor
- Copy Constructor
- Assignment Operator
- Destructor
How you define these will depend on the situations. But things to watch out for:
您如何定义这些将取决于具体情况。但要注意的事项:
- Default Construction: Set pointer to NULL
- Copy Constructor: Use the Copy and Swap ideum to provide to the "Strong Exception Guarantee"
- Assignment operator: Check for assignment to self
- Destructor: Guard against exceptions propagating out of the destructor.
默认构造:将指针设置为NULL
复制构造函数:使用复制和交换标识提供“强异常保证”
分配操作员:检查分配给自己
析构函数:防止从析构函数中传播的异常。
#3
1
try to read this.
试着读一下。
http://www.icu-project.org/docs/papers/cpp_report/the_anatomy_of_the_assignment_operator.html
is a very good analysis of Assignment operator
是一个非常好的分配运算符的分析
#4
-2
I have no idea about exception safely here but I go this way. Let's imagine it's a templated array wrapper. Hope it helps :)
我在这里安全地不知道异常,但我这样做了。让我们想象一下它是一个模板化的数组包装器。希望能帮助到你 :)
Array(const Array& rhs)
{
mData = NULL;
mSize = rhs.size();
*this = rhs;
}
Array& operator=(const Array& rhs)
{
if(this == &rhs)
{
return *this;
}
int len = rhs.size();
delete[] mData;
mData = new T[len];
for(int i = 0; i < len; ++i)
{
mData[i] = rhs[i];
}
mSize = len;
return *this;
}