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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:13:37  来源:igfitidea点击:

call copy constructor from assignment operator function

c++visual-studio

提问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 otherof 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 otherof type FeatureValue.

您不能像任何其他方法一样直接调用构造函数。您正在做的实际上是声明一个名为othertype的变量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::vectorinstead of newand delete. Then you don't need to write your own copy constructor or assignment operator.

更好的是,使用 astd::vector代替newand 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_valuehas an indeterminate value when the copy constructor starts running - you can assign to it, but to read from it is undefined behaviour, and to delete[]it considerably worse (if anything can be worse than UD! ;-)). So, just leave out that delete[]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_valueis 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 newcan't get the memory it wants), then the FeatureValueobject is left with an invalid state (e.g. m_valuemight 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_sizeand m_value, and using it ala:

你真的应该更系统地解决这个问题......要么一步一步地写出来,要么实现一个有保证的非抛出swap()方法(容易做到......只是std::swap()m_sizeand 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_valuearray around longer than necessary, increasing peak memory usage... you could call clear(). 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_valuememory - instead always doing another newfor other(that can lead to reduced memory usage but isn't always worthwhile).

  • 将任何现有m_value数组保留的时间超过必要的时间,从而增加峰值内存使用量……您可以调用clear(). 在实践中,大多数非平凡的程序不会关心这一点,除非所讨论的数据结构包含大量数据(例如,PC 应用程序的数百兆字节或千兆字节)。

  • 甚至不尝试重用现有m_value内存 - 而是总是做另一个newfor other(这可能会导致内存使用量减少,但并不总是值得的)。

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.