CArray 不会在内存重新分配时调用复制构造函数,现在怎么办?

发布于 2024-09-03 04:05:10 字数 755 浏览 6 评论 0原文

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

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 用于任何严肃的事情是一个坏主意吗?

Suppose I have a class that requires copy constructor to be called to make a correct copy of:

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

Now the trouble is that CArray doesn't call copy constructors on its elements when reallocating memory (only memcpy from the old memory to the new), e.g. this code

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

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

results in

47 47
-572662307 47

I don't get this. Why is it that std::vector can copy the same objects properly and CArray can't? What's the lesson here? Should I use only classes that don't require explicit copy constructors? Or is it a bad idea to use CArray for anything serious?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

长发绾君心 2024-09-10 04:05:10

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

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

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

无论如何执行此操作通常是一个好主意,以避免复制构造和赋值之间的行为不一致。

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

  1. 返回非常量引用是 operator= 的标准,因为它与基元类型的语义匹配。
  2. 按值传递参数是复制原始对象的最简单方法,并保证在复制构造函数失败时该对象不会受到影响。
  3. 对 swap 的调用以永远不会抛出异常的方式切换传入的副本与该对象,从而以完全异常安全的方式实现分配。

在这种情况下,只分配数字会更简单,但我习惯性地以这种方式实现所有分配,以避免如果未来的维护者使复制抛出异常成为可能,我会陷入困境。

The copied pointer still points to the original number, which no longer exists, since the array has been reallocated due to the resize.

I'm guessing that CArray uses assignment rather than copy-construction. Define an assignment operator to see if this fixes it:

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

It's generally a good idea to do this anyway, to avoid inconsistent behaviour between copy-construction and assignment.

FYI, the above code uses an idiomatic approach to implementing assignment semantics with strong exception-safety guarantees:

  1. Returning a non-const reference is very much the standard for operator=, since it matches the semantics of primitive types.
  2. Passing the parameter by value is the easiest way to make a copy of the original, and guarantees that this object won't be affected if the copy constructor fails.
  3. The call to swap switches the passed-in copy with this object in a way that will never throw an exception, thus effecting the assignment in a completely exception-safe manner.

In this case, it would be simpler to just assign the number, but I habitually implement all my assignments this way to avoid being caught with my pants down if a future maintainer makes it possible for copying to throw an exception.

反话 2024-09-10 04:05:10

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

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

Or is it a bad idea to use CArray for anything serious?

Yes, it's an exceptionally bad idea. Use std::vector whenever possible.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文