CArray不会在内存重新分配上调用复制构造函数,现在是什么?

时间:2010-05-28 10:58:14

标签: c++ windows mfc copy-constructor

假设我有一个类需要调用复制构造函数来制作正确的副本:

struct CWeird
{
    CWeird() { number = 47; target = &number; }

    CWeird(const CWeird &other) : number(other.number), target(&number) { }

    const CWeird& operator=(const CWeird &w) { number = w.number; return *this; }

    void output()
    {
        printf("%d %d\n", *target, number);
    }

    int *target, number;
};

现在麻烦的是CArray在重新分配内存时只调用其元素上的复制构造函数(只有memcpy从旧内存到新内存),例如:这段代码

CArray<CWeird> a;
a.SetSize(1);
a[0].output();

a.SetSize(2);
a[0].output();

结果

47 47
-572662307 47

我不懂。为什么std :: vector可以正确复制相同的对象而CArray不能?这是什么教训?我应该只使用不需要显式拷贝构造函数的类吗?或者将CArray用于任何严肃的事情是不是一个坏主意?

2 个答案:

答案 0 :(得分:3)

复制的指针仍指向原始编号,该编号不再存在,因为由于调整大小而重新分配了数组。

我猜测CArray使用赋值而不是复制构造。定义赋值运算符以查看是否可以修复它:

CWeird& operator=(CWeird w) { swap(w); return *this; }
void swap(CWeird& w) { int t = number; number = w.number; w.number = t; }

无论如何,这通常是一个好主意,以避免复制构造和分配之间的不一致行为。

仅供参考,上述代码使用惯用方法实现具有强大异常安全保证的赋值语义:

  1. 返回非const引用是operator=的标准,因为它与原始类型的语义相匹配。
  2. 按值传递参数是制作原件副本的最简单方法,并保证在复制构造函数失败时此对象不会受到影响。
  3. 对swap的调用以永远不会抛出异常的方式切换传入的副本与此对象,从而以完全异常安全的方式影响赋值。
  4. 在这种情况下,只分配数字会更简单,但我习惯性地以这种方式实现我的所有任务,以避免因为未来的维护者使复制成为异常而陷入困境。

答案 1 :(得分:0)

  

或者将CArray用于任何严肃的事情是不是一个坏主意?

是的,这是一个非常糟糕的主意。尽可能使用std::vector