从赋值运算符函数调用复制构造函数

时间:2013-07-05 02:48:49

标签: c++ visual-studio

我有一个指向动态分配数组的类,所以我创建了复制构造函数和赋值运算符函数。由于复制构造函数和赋值运算符函数执行相同的工作,我从赋值运算符函数调用复制构造函数,但得到"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;
}

4 个答案:

答案 0 :(得分:18)

违规行不符合你的想法。它实际上声明了other类型的变量FeatureValue。这是因为构造函数没有名称而且无法直接调用。

只要操作符未声明为虚拟,就可以安全地从构造函数中调用复制赋值运算符。

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;
}

这可能只是花花公子,或者你可以使用典型的副本&amp; amp;在Vaughn Cato's answer

中建议的交换习语

答案 1 :(得分:11)

您不能像任何其他方法一样直接调用构造函数。你正在做的是实际声明一个名为other FeatureValue的变量。

查看复制和交换习惯用法,以避免赋值运算符和复制构造函数之间的重复:What is the copy-and-swap idiom?

更好的是,使用std::vector代替newdelete。然后,您不需要编写自己的复制构造函数或赋值运算符。

答案 2 :(得分:3)

简短回答 - 不要这样做。

详细说明:

// 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;
}

注意:

  • 当调用复制构造函数时,它正在引用正在复制的对象来构造新对象,但默认构造函数不会在复制构造函数之前运行。这意味着当复制构造函数开始运行时m_value具有不确定的值 - 您可以为其分配,但是从中读取未定义的行为,并且delete[]它更糟糕(如果有什么可能比UD!;-))。所以,请忽略delete[]行。

接下来,如果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;
}

这个问题是如果FeatureValue的创建失败(例如因为new无法获得它想要的内存),那么FeatureValue对象会留下无效状态(例如{ {1}}可能指向太空)。稍后当析构函数运行并执行m_value时,您有未定义的行为(您的程序可能会崩溃)。

你真的应该更系统地解决这个问题......要么一步一步地写出来,要么实施一个有保证的非投掷delete[] m_value方法(很容易......只是swap() {{ 1}}和std::swap(),并使用它ala:

m_size

这很简单,但它有一些性能/效率问题:

  • 将任何现有的m_value数组保持在必要的时间以上,增加峰值内存使用量......您可以调用FeatureValue& FeatureValue::operator=(FeatureValue other) { swap(other); return *this; } 。在实践中,大多数非平凡的程序都不会关心这一点,除非有问题的数据结构存在大量数据(例如,PC应用程序的数百兆字节或千兆字节)。

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

最终,可能存在不同的复制构造函数和new的原因 - 而不是让编译器自动创建另一个 - 是最优化的实现不能 - 通常 - 相互利用你希望。

答案 3 :(得分:0)

语句FeatureValue(other);实际上调用了复制构造函数来创建一个新的Featurevalue对象,该对象与*this无关。