c++ - C++:使用 cout 导致变量值发生变化
问题描述
我正在学习如何使用类并编写了以下代码:
#include<iostream>
using namespace std;
class DQNode
{
public:
int data;
DQNode *next, *last;
DQNode(int num, DQNode *n, DQNode *l)
{
data = num;
next = n;
last = l;
}
};
class Deque
{
private:
DQNode *top, *bottom;
int size;
public:
Deque()
{
top = NULL;
bottom = NULL;
size = 0;
}
void addFirst(int inp)
{
DQNode nn(inp, NULL, top);
if(top != NULL)
{
(*top).next = &nn;
}
top = &nn;
if(bottom == NULL)
{
bottom = &nn;
}
}
void PrintAll()
{
cout<<top->data<<endl;
}
};
int main()
{
Deque n;
n.addFirst(5);
cout<<"yo"<<endl;
n.PrintAll();
}
上面的代码打印“yo”后跟一个随机整数,有趣的部分是删除cout<<"yo"<<endl;
输出完全符合预期,即 5。所以,如果有人明白出了什么问题,请帮助我。
解决方案
你有未定义的行为。
当您违反规则时,就会发生这种情况。如果幸运的话,您的程序会因分段错误而崩溃。其他时候,你运气不好,你的程序行为不端。
你是怎么打破规则的?好吧,你访问了一个死对象。
问题的根源发生在您的addFirst
函数中。您将 a 存储DQNode
在您的Deque
但该节点死亡。
您会看到,所有具有自动存储功能的局部变量都有明确定义的生存和死亡规则。它们的生命周期是基于范围的。它看起来像这样:
// Lifetimes
void addFirst(int inp) // inp
{ // |
DQNode nn(inp, NULL, top); // | nn
if(top != NULL) // | |
{ // | |
(*top).next = &nn; // | +--- <- top->next
} // | |
top = &nn; // | +--- <- top
if(bottom == NULL) // | |
{ // | |
bottom = &nn; // | +--- <- bottom
} // | |
} // | X -- nn dies
// X -- inp dies
具有自动生命周期的变量首先生存,最后死亡。没有例外。在}
函数末尾的字符处,即其作用域结束的地方,所有局部变量都被销毁。nn
首先,然后inp
。
此时, top
, bottom
ortop->next
仍指向nn
, 已被销毁!
然后,在你的PrintAll
函数中读取指针=,它指向一个被破坏的变量。那时,您可以读取程序该点堆栈上的任何内容。一个简单的调用就cout
可以在原来的地方分配变量nn
,并分配任何需要的值。您的指针仍将指向那里,并打印垃圾。
你能为这个做什么?
好吧,您不想要自动存储。它不会做你想做的事。您希望控制变量的生命周期,并在您决定何时不再需要它们时释放它们。这称为免费商店。您使用动态分配在那里创建对象:
void addFirst(int inp)
{
// new will dynamically allocate the object on the free store.
DQNode* nn = new DQNode(inp, NULL, top);
if(top != NULL)
{
(*top).next = nn;
}
top = nn;
if(bottom == NULL)
{
bottom = nn;
}
} // the `nn` pointer dies, but not the object it refers to!
但是,您的程序永远不会自行解除分配变量,您必须手动执行此操作,否则会发生内存泄漏。
~Deque() {
// traverse the tree
// delete all node in the tree
}
幸运的是,还有一个称为 a 的工具std::unique_ptr
,它会在分配的对象死亡时负责删除它。
名称unique_ptr来自唯一所有者。内存的所有权可以转让,但始终只有一个所有者。当所有者死亡时,它会从空闲存储中释放对象:
// create a int equal to 1 on the free store using dynamic allocation
std::unique_ptr<int> int_a = std::make_unique<int>(1);
std::unique_ptr<int> int_b = nullptr;
// transfer ownership from int_a to int_b
int_b = std::move(int_a);
// int_a is null
// int_b point to a int equal to 1
// This is disallowed, you cannot have two owner, so no copy
// int_a = int_b;
// can have an observing raw pointer:
int* int_c = int_b.get();
// transfer ownership back
int_a = std::move(int_b);
// at that point int_a is equal to int_c
// int_a is the owner, int_c simply point to the same int.
// int_b is null
// Set the last owner to null:
int_a = nullptr;
// the int has been destroyed because there is no owner left.
// int_a is null, int_b is null
// int_c is a dangling pointer, point to the dead object.
推荐阅读
- javascript - 如果条件不运行但其他条件有效
- android - 更新到 Target API 26 后,不再支持少数手机
- jquery - 如何将数组的每个项目拆分为新的div
- mysql - Mysql加入三张表并分组
- javascript - 如何通过将鼠标悬停在树下方的元素上来隐藏树上方的元素
- mongodb - Mongo 自定义配置未连接到 Mongo 实例
- chef-infra - 将 inspec 配置文件上传到 Chef Automate 时出现 Inspec 4.16.0 问题
- angular - 在 Angular 中导入数据
- python - 如何使用 Python 以编程方式将行添加到现有 Excel 表
- python-3.x - 为 twitter 注册 webhook 的程序是什么?