18

请写一个副本构造函数和赋值运算符在 C++ 中需要执行的任务列表,以保持异常安全,避免内存泄漏等。

4

4 回答 4

15

首先确定你真的需要支持副本。大多数情况下并非如此,因此禁用两者是可行的方法。

有时,您仍然需要为多态层次结构中的类提供重复项,在这种情况下:禁用赋值运算符,编写(受保护?)复制构造函数,并提供虚拟 clone() 函数。

否则,如果您正在编写一个值类,您将回到 Coplien 的正交规范形式的领域。如果您有一个无法简单复制的成员,则需要提供一个复制构造函数、一个析构函数、一个赋值运算符和一个默认构造函数。这条规则可以细化,例如参见:The Law of The Big Two

我还建议查看有关赋值运算符的 C++ 常见问题解答,以及复制和交换成语以及GOTW

于 2008-10-18T12:14:53.987 回答
4

编译器生成的版本适用于大多数情况。

当您的对象包含 RAW 指针(没有 RAW 指针的参数)时,您需要更加努力地思考这个问题。所以你有一个 RAW 指针,第二个问题是你是否拥有指针(它是否被你删除了)?如果是这样,那么您将需要应用规则 4。

拥有超过 1 个 RAW 指针变得越来越难以正确执行(复杂性的增加也不是线性的 [但这是观察性的,我没有真正的统计数据来支持该陈述])。因此,如果您有超过 1 个 RAW 指针,请考虑将每个指针包装在自己的类中(某种形式的智能指针)。

4 规则:如果对象是 RAW 指针的所有者,那么您需要定义以下 4 个成员以确保正确处理内存管理:

  • 构造函数
  • 复制构造函数
  • 赋值运算符
  • 析构函数

您如何定义这些将取决于具体情况。但需要注意的事项:

  • 默认构造:将指针设置为 NULL
  • Copy Constructor:使用Copy and Swap ideum来提供“强异常保证”
  • 赋值运算符:检查赋值给 self
  • 析构函数:防止异常从析构函数中传播出去。
于 2008-10-18T16:04:24.493 回答
1

尝试阅读此内容。

http://www.icu-project.org/docs/papers/cpp_report/the_anatomy_of_the_assignment_operator.html

是一个很好的赋值算子分析

于 2008-11-06T15:56:20.947 回答
-2

我不知道这里安全异常,但我走这条路。让我们想象它是一个模板化的数组包装器。希望能帮助到你 :)

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;
    }
于 2008-10-18T11:30:04.983 回答