CArray doesn't call copy constructors on memory reallocations, now what?

痞子三分冷 提交于 2019-12-10 11:32:32

问题


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?


回答1:


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.




回答2:


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

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



来源:https://stackoverflow.com/questions/2928369/carray-doesnt-call-copy-constructors-on-memory-reallocations-now-what

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!