提问人:Imago 提问时间:3/13/2019 更新时间:1/11/2020 访问量:134
“三法则”的实施出了问题
Implementation of "Rule of Three" gone wrong
问:
下面是“三法则”的错误实现,我试图理解。
调试程序时,我发现调试器在清理时遇到了问题,可以通过在复制构造函数中定义或简单地将其设置为合理的值来解决。int *k
int *k = nullptr
但是,我不明白程序产生的错误(访问违规)是如何产生的。
我确实知道,在复制赋值构造函数不再指向有效的内存地址之后。v1
int *k
class Vector2 {
public:
std::string name = "default";
int* k;
Vector2(int s, std::string n) : k(new int[s]), name(n) {
}
Vector2(const Vector2 &other) {
std::cout<< "Copy constructor: " << name << std::endl;
}
~Vector2() {
std::cout << "Deleting: " << name << std::endl;
delete[] k;
}
void swap(Vector2& other) {
using std::swap;
swap(k, other.k);
}
Vector2& operator=(Vector2 other) {
std::cout << "Copy assignment constructor: " << name << std::endl;
swap(other);
return *this;
}
};
int main() {
Vector2 v1 = Vector2(2, "v1");
Vector2 v2 = Vector2(4, "v2");
v1 = v2;
std::cout << &v1 << " " << &v2 << std::endl;
std::cout << &v1.k << " " << &v2.k << std::endl;
return 0;
}
下面是上述程序的控制台输出:
Copy constructor: default
Copy assignment constructor: v1
Deleting: default
0000001B5611FA28 0000001B5611FA78
0000001B5611FA50 0000001B5611FAA0
Deleting: v2
Deleting: v1
16:18:42: The program has unexpectedly finished.
答:
构造使用复制构造函数,该构造函数不会创建指向值的新副本。您的复制构造函数甚至可能不会复制,因为它是 POD 类型,因此不一定是默认构造或默认复制。other
operator=
k
然后,当它被破坏时,它会试图摧毁它两次。或者,根据堆栈布局等随机因素,它可能根本不会复制,然后尝试指向无效指针。k
delete
评论
k
v1
operator=
v1
swap
k
other.k
您的问题在Vector2(const Vector2 &other)
您可以通过传递值来隐式使用此构造函数;但是您未能将 k 赋值给该构造函数中的任何值。operator =
这会导致交换将有效的 k 替换为无效的 k,然后删除无效的 k;导致您的崩溃。
这实际上很简单:您的复制构造函数不会创建副本。实际上,它不会初始化任何成员,因此该构造函数创建的任何实例都充满了废话。
对于复制构造函数的调用被调用来创建(这是三分法则的重点),所以充满了废话。
然后你把 (aka ) 的有效性换成 的蹩脚的 .operator=(Vector2 other)
other
other
k
this
v1
k
other
然后,当调用析构函数 of 时,它会调用一个蹩脚的 --> 访问冲突。v1
delete[] k
k
溶液
使复制构造函数 制作副本。或者至少,让它正确初始化(例如 to )。k
nullptr
可以通过布置事件的确切顺序来得出解决方案,例如:更多的打印输出和测试,在以下情况下调用哪些参数:
起步时间:v1 = v2;
v2
使用参数 other(无论 other 是什么)调用 copy 构造函数,特别是:ITS 不指向有效内存。为简单起见,我们将其称为新的 Vector2 v3。int* k
- 复制分配构造函数现在使用 v3 调用。
- 然后我们开始交换。
该错误实际上出现在复制构造函数中,因为在步骤 1 中未正确初始化。v3
第 2 步和第 3 步基本上是“隐藏”,将错误从 转移到 .v3
v1
现在有趣的问题是,实际上是如何生成的?不是默认构造函数!v3
评论
delete