函数调用后释放变量

Variable being deallocated after function call

本文关键字:变量 释放 函数调用      更新时间:2023-10-16

我是C++的初学者,遇到了一个问题。请参阅下面的代码。内联注释中描述了此问题。

#include<iostream>
#include<tuple>
#include<vector>
// #include "test.hpp"
using namespace std;
vector<string*> test();
int main() {
vector<string*> ret = test();
cout << ret.back() << endl; //Outputs: Memory of String str
cout << *ret.back() << endl; //Outputs: random undefined behavior
//I want this to output "s"
}
vector<string*> test() {
vector<string*> ret;
string str = "t";
ret.push_back(&str);
cout << ret.back() << endl; //Outputs: Memory of String str
cout << *ret.back() << endl; //Outputs: "t"
str[0] = 's';
cout << ret.back() << endl; //Outputs: Memory of String str
cout << *ret.back() << endl; //Outputs: "s"
return ret;
}

基本上,我希望拥有它,以便我可以在函数体中声明一个对象,将其添加到向量中,并能够在函数中再次修改该对象(将来的任何时间(,并且能够在我有此向量的任何地方看到这些更改。这在 Java 中很容易完成,但我在 C++ 中很难做到这一点。

当创建对象的作用域离开时,声明为具有自动生存期的对象始终不复存在。

如果希望对象在创建对象时超出其创建范围,则必须使用new关键字创建具有动态生存期的对象。 但请记住,C++没有垃圾回收器,因此每次使用new时,您都必须在完成创建的对象后delete它。 最好的方法是使用某种形式的智能指针,如std::unique_ptrstd::shared_ptr(使用取决于您的具体情况(:

std::vector<std::unique_ptr<std::string>> test() {
std::vector<std::unique_ptr<std::string>> ret;
std::unique_ptr<std::string> str = std::make_unique<std::string>("t");
ret.push_back(std::move(str));
//...
return ret;
}

(std::make_unique使用new创建一个新对象并返回一个std::unique_ptr(


在这种特殊情况下,在向量中存储指向字符串的指针实际上没有任何优势。std::string对象本质上是指向字符数组的智能指针,因此您可以直接存储对象:

std::vector<std::string> test() {
std::vector<std::string> ret;
ret.push_back("t");
//...
return ret;
}

停止使用指针。它们在C++中占有一席之地,但在您发布的代码中没有。

具体问题是这样的:

string str = "t";
ret.push_back(&str);

您正在存储指向函数本地std::string对象的指针。在函数结束时,std::string超出范围并被销毁,留下一个悬空的指针和未定义的行为。

vector<string*> ret;更改为vector<string> ret;。存储对象而不是指针,值语义更容易推理。标准库容器和字符串旨在做正确的事情,并使这一切变得简单。

你想要改变这个:

string str = "t";
ret.push_back(&str);

对此:

string* str = new string("t");
ret.push_back(str);

问题是在你的原始示例中,当你退出test()时,你的字符串会被销毁,这意味着它的内存地址现在不指向任何内容。若要避免这种情况,您需要使用指针在堆上分配str,以便在退出test()后不会清理内存。

请记住,无论何时在C++中手动分配内存,都必须将其解除分配以避免内存泄漏:

for (string* i : ret) {
delete i;
}

您正在推回局部变量的地址。当变量超出范围时,将释放该内存地址。

您可以改用unique_ptr或shared_ptr,如下所示:

#include<iostream>
#include<tuple>
#include<vector>
#include<memory>
// #include "test.hpp"
using namespace std;
vector<std::shared_ptr<string>> test();
int main() {
vector<std::shared_ptr<string>> ret = test();
cout << ret.back() << endl; //Outputs: Memory of String str
cout << *(ret.back()) << endl; //Outputs: "t"
}
vector<std::shared_ptr<string>> test() {
vector<std::shared_ptr<string>> ret;
const auto str = std::make_shared<string>("t");
ret.push_back(str);
cout << ret.back() << endl; //Outputs: Memory of String str
cout << *(ret.back()) << endl; //Outputs: "t"
return ret;
}