C++ 从赋值运算符函数调用复制构造函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17480396/
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
call copy constructor from assignment operator function
提问by stackunderflow
I have a class with a point to dynamically allocated array, so I created copy constructor and assignment operator function. Since copy constructor and assignment operator function do the same work, I call copy constructor from the assignment operator function but get "error C2082: redefinition of formal parameter"
. I am using Visual Studio 2012.
我有一个指向动态分配数组的类,所以我创建了复制构造函数和赋值运算符函数。由于复制构造函数和赋值运算符函数执行相同的工作,因此我从赋值运算符函数调用复制构造函数但 get "error C2082: redefinition of formal parameter"
。我正在使用 Visual Studio 2012。
// default constructor
FeatureValue::FeatureValue()
{
m_value = NULL;
}
// copy constructor
FeatureValue::FeatureValue(const FeatureValue& other)
{
m_size = other.m_size;
delete[] m_value;
m_value = new uint8_t[m_size];
for (int i = 0; i < m_size; i++)
{
m_value[i] = other.m_value[i];
}
}
// assignment operator function
FeatureValue& FeatureValue::operator=(const FeatureValue& other)
{
FeatureValue(other); // error C2082: redefinition of formal parameter
return *this;
}
回答by Captain Obvlious
The offending line isn't what you think it is. It actually declares a variable other
of type FeatureValue
. This is because constructors to not have names and cannot be called directly.
违规行不是您认为的那样。它实际上声明了一个other
类型为 的变量FeatureValue
。这是因为构造函数没有名称并且不能直接调用。
You can safely invoke the copy assignment operator from the constructor as long as the operator is not declared virtual.
只要运算符未声明为虚拟,您就可以安全地从构造函数调用复制赋值运算符。
FeatureValue::FeatureValue(const FeatureValue& other)
: m_value(nullptr), m_size(0)
{
*this = other;
}
// assignment operator function
FeatureValue& FeatureValue::operator=(const FeatureValue& other)
{
if(this != &other)
{
// copy data first. Use std::unique_ptr if possible
// avoids destroying our data if an exception occurs
uint8_t* value = new uint8_t[other.m_size];
int size = other.m_size;
for (int i = 0; i < other.m_size; i++)
{
value[i] = other.m_value[i];
}
// Assign values
delete[] m_value;
m_value = value;
m_size = size;
}
return *this;
}
This will works just dandy or you can use the typical guidelines for the copy & swap idiom suggested in Vaughn Cato's answer
这将非常有效,或者您可以使用Vaughn Cato 的回答中建议的复制和交换习语的典型指南
回答by Vaughn Cato
You can't directly call a constructor like you would any other method. What you are doing is actually declaring a variable called other
of type FeatureValue
.
您不能像任何其他方法一样直接调用构造函数。您正在做的实际上是声明一个名为other
type的变量FeatureValue
。
Take a look at the copy-and-swap idiom for a good way to avoid duplication between the assignment operator and the copy constructor: What is the copy-and-swap idiom?
查看 copy-and-swap 惯用语,了解避免赋值运算符和复制构造函数之间重复的好方法:什么是 copy-and-swap 惯用语?
Even better, use a std::vector
instead of new
and delete
. Then you don't need to write your own copy constructor or assignment operator.
更好的是,使用 astd::vector
代替new
and delete
。那么您就不需要编写自己的复制构造函数或赋值运算符。
回答by Tony Delroy
Short answer - don't do it.
简短的回答 - 不要这样做。
Details:
细节:
// copy constructor
FeatureValue::FeatureValue(const FeatureValue& other)
{
m_size = other.m_size;
delete[] m_value; // m_value NOT INITIALISED - DON'T DELETE HERE!
m_value = new uint8_t[m_size];
for (int i = 0; i < m_size; i++)
{
m_value[i] = other.m_value[i];
}
}
// assignment operator function
FeatureValue& FeatureValue::operator=(const FeatureValue& other)
{
FeatureValue(other); // error C2082: redefinition of formal parameter
return *this;
}
Notes:
笔记:
- When the copy constructor is called, it's constructing the new object with reference to the object being copied, but the default constructor does not run before the copy constructor. This means
m_value
has an indeterminate value when the copy constructor starts running - you can assign to it, but to read from it is undefined behaviour, and todelete[]
it considerably worse (if anything can be worse than UD! ;-)). So, just leave out thatdelete[]
line.
- 当复制构造函数被调用时,它会参考被复制的对象来构造新对象,但默认构造函数不会在复制构造函数之前运行。这意味着
m_value
当复制构造函数开始运行时有一个不确定的值——你可以分配给它,但从中读取是未定义的行为,而且delete[]
对它来说更糟糕(如果有什么比 UD 更糟糕的话!;-))。所以,只要省略那条delete[]
线。
Next, if operator=
tries to leverage the functionality from the copy constructor, it has to first release any existing data m_value
is pointing at or it will be leaked. Most people try to do that as follows (which is broken) - I think this is what you were trying for:
接下来,如果operator=
试图利用复制构造函数的功能,它必须首先释放任何m_value
指向的现有数据,否则它将被泄漏。大多数人尝试按以下方式执行此操作(已损坏)-我认为这就是您要尝试的:
FeatureValue& FeatureValue::operator=(const FeatureValue& other)
{
// WARNING - this code's not exception safe...!
~FeatureValue(); // call own destructor
new (this) FeatureValue(other); // reconstruct object
return *this;
}
The problem with this is that if the creation of FeatureValue fails (e.g. because new
can't get the memory it wants), then the FeatureValue
object is left with an invalid state (e.g. m_value
might be pointing off into space). Later when the destructor runs and does a delete[] m_value
, you have undefined behaviour (your program will probably crash).
这样做的问题是,如果 FeatureValue 的创建失败(例如,因为new
无法获得它想要的内存),那么FeatureValue
对象将处于无效状态(例如,m_value
可能指向空间)。稍后当析构函数运行并执行 a 时delete[] m_value
,您有未定义的行为(您的程序可能会崩溃)。
You really should approach this more systematically... either writing it out step by step, or perhaps implementing a guaranteed non-throwing swap()
method (easy to do... just std::swap()
m_size
and m_value
, and using it ala:
你真的应该更系统地解决这个问题......要么一步一步地写出来,要么实现一个有保证的非抛出swap()
方法(容易做到......只是std::swap()
m_size
and m_value
,并使用它ala:
FeatureValue& FeatureValue::operator=(FeatureValue other)
{
swap(other);
return *this;
}
That's easy and clean, but it has a couple minor performance/efficiency issues:
这既简单又干净,但它有几个小的性能/效率问题:
keeping any existing
m_value
array around longer than necessary, increasing peak memory usage... you could callclear()
. In practice, most non-trivial programs wouldn't care about this unless the data structure in question was holding huge amounts of data (e.g. hundreds of megabytes or gigabytes for a PC app).not even trying to reuse the existing
m_value
memory - instead always doing anothernew
forother
(that can lead to reduced memory usage but isn't always worthwhile).
将任何现有
m_value
数组保留的时间超过必要的时间,从而增加峰值内存使用量……您可以调用clear()
. 在实践中,大多数非平凡的程序不会关心这一点,除非所讨论的数据结构包含大量数据(例如,PC 应用程序的数百兆字节或千兆字节)。甚至不尝试重用现有
m_value
内存 - 而是总是做另一个new
forother
(这可能会导致内存使用量减少,但并不总是值得的)。
Ultimately, the reasons there can be distinct copy constructor and operator=
- rather than having the compiler automatically create one from the other - is that optimally efficient implementations can't - in general - leverage each other in the way you'd hoped.
最终,可能存在不同的复制构造函数的原因operator=
——而不是让编译器自动从另一个创建一个——是最佳高效的实现不能——通常——以您希望的方式相互利用。
回答by witrus
The statement FeatureValue(other);
actually invokes the copy constructor to create a new Featurevalue object,which has nothing to do with *this
.
该语句FeatureValue(other);
实际上调用了复制构造函数来创建一个新的 Featurevalue 对象,该对象与*this
.