CArray 不会在内存重新分配时调用复制构造函数,现在怎么办?
假设我有一个类需要调用复制构造函数来进行正确的复制:
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
复制的指针仍然指向原始数字,但该数字已不存在,因为由于调整大小而重新分配了数组。
我猜测 CArray 使用赋值而不是复制构造。定义一个赋值运算符以查看是否可以修复该问题:
无论如何执行此操作通常是一个好主意,以避免复制构造和赋值之间的行为不一致。
仅供参考,上面的代码使用惯用的方法来实现赋值语义,并具有强大的异常安全保证:
operator=
的标准,因为它与基元类型的语义匹配。在这种情况下,只分配数字会更简单,但我习惯性地以这种方式实现所有分配,以避免如果未来的维护者使复制抛出异常成为可能,我会陷入困境。
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:
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.
是的,这是一个非常糟糕的主意。尽可能使用
std::vector
。Yes, it's an exceptionally bad idea. Use
std::vector
whenever possible.