更新时间:2023-11-13 13:53:52
复制的指针仍然指向原始数字,其中没有更长的存在,因为数组已经由于调整大小重新分配。
我猜猜CArray使用赋值,而不是复制构造。定义赋值运算符以查看是否可以修复它:
CWeird& operator =(CWeird w){swap(w); return * this; }
void swap(CWeird& w){int t = number; number = w.number; w.number = t; }
这通常是一个好主意,以避免复制构造和赋值之间不一致的行为。
FYI,上述代码使用惯用的方法来实现具有强大的异常安全保证的赋值语义:
operator =
的标准,因为它匹配原始类型的语义。在这种情况下,只是分配数字会更简单,但我习惯性地实现我的所有分配,以避免被抓住我的裤子,如果一个未来的维护者可以复制投掷一个例外。
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?
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:
operator=
, since it matches the semantics of primitive types.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.