我有一个功能,我无法更改功能参数。我需要返回一个const引用到这个函数中创建的std :: string。我尝试使用boost shared_ptr,但这不起作用。为什么?我如何使这项工作?
const std::string& getVal(const std::string &key) {
boost::shared_ptr<std::string> retVal(new std::string());
... //build retVal string with += operator based on key
return *retVal;
}
答案 0 :(得分:3)
您不能从具有c ++的函数返回对局部变量的引用。虽然在c ++ 0x中这是可能的。
在堆上分配字符串并稍后手动清理:
如果无法更改函数的界面,则需要在堆上创建它,然后在之后手动删除它。
//Remember to free the address that getVal returns
const std::string& getVal(const std::string &key) {
std::string *retVal = new std::string();
... //build retVal string with += operator based on key
return *retVal;
}
相同的解决方案,但不能手动:
如果忘记手动释放,上述内容最终会导致内存泄漏。我建议将此调用包装到一个类中并使用RAII。即在构造函数中,调用getVal并将此类的成员设置为指向它。在你的类的析构函数中,你将删除它。
为什么使用shared_ptr提供的代码不起作用:
shared_ptr通过引用计数工作。由于您正在销毁唯一的shared_ptr对象(按范围),因此没有引用,并且将释放内存。为了使这个工作你必须返回一个shared_ptr,但你说你不能这样做。
答案 1 :(得分:3)
您需要返回boost shared_ptr,而不是std :: string。一旦函数退出,堆栈上的shared_ptr将超出范围,因为只有一个引用它将被删除。您还需要返回副本而不是引用。
你永远不应该返回对堆栈变量的引用,因为只要该函数存在,它就会被删除。
如果你不能改变返回类型那么唯一的(icky)选项是在堆上分配字符串,返回对指针的引用,并确保调用代码知道它是一个指针,然后删除它。 / p>
E.g。
const std::string& getVal(const std::string &key) {
return *(new std::string("Something"));
}
// get the val, remember we must delete this pointer!
std::string* pString = &getVal("SomeKey");
delete pString;
答案 2 :(得分:2)
这不是一个提升问题。您不能返回对局部变量的引用,因为一旦函数终止,该变量将不再存在。在这种情况下,你应该真的返回一个值。但是,您可以使用的一个方法是将局部变量设置为静态,但这可能会导致并发性和其他问题。
答案 3 :(得分:0)
由于您无法更改函数的签名,因此可以返回对静态变量的引用:
const std::string& getVal(const std::string &key) {
static std::string retVal;
... //build retVal string with += operator based on key
return retVal;
}
但这种方法存在严重问题。它本质上不是线程安全的。即使您的应用程序不是多线程的,也可能会导致问题,具体取决于调用者保留引用的时间。
如果您的应用程序不是多线程的,并且每次调用getVal()都会立即使用或复制字符串,那么您可以放弃使用它。但我强烈建议只返回一个std :: string。
答案 4 :(得分:0)
因为你想要的是const引用,你可以按值返回并让调用者通过const引用接收它。
答案 5 :(得分:0)
需要考虑的另一点是,标准允许编译器在可能的情况下优化副本。标准是指 copy elision ,但大多数人都知道它为“命名返回值优化”,请参阅here。
基本概念是,在可能的情况下,编译器将直接在作为函数调用结果的对象上构造本地对象:
class A {};
A foo () {
A a; // #1
return a;
}
void bar () {
A b = foo(); // #2
}
在上面的例子中,'a'将与bar中的'b'在同一位置构建,因此当函数返回时根本不需要复制。总之,在测试编译器以查看它是否执行此优化时可能是值得的。如果您感兴趣,标准参考为12.8 / 15.