如何正确返回std :: string(或如何正确使用返回值)

时间:2011-01-06 22:08:33

标签: c++ return-value stdstring

假设您有一个全局类(例如可用于应用程序的运行时)

class MyClass {
  protected:
    std::string m_Value;
  public:
    MyClass () : m_Value("hello") {}
    std::string value() { return m_Value; }      
};

MyClass v1;

当我做

时,使用第一个表单会给我带来奇怪的行为
printf("value: %s\n", v1.value().c_str());

看起来字符串在printf可以使用之前从内存中消失了。 有时它打印值:hello其他时候它会崩溃或什么都不打印。

如果我第一次复制字符串

   std::string copiedString = v1.value();
   printf("value: %s\n", copiedString.c_str());
事情确实有效。

当然必须有办法避免使用临时字符串。

编辑:所以共识是使用const std :: string&返回值。

我知道每个人都说原始代码应该没问题,但我可以告诉你 我在Windows CE上看到MSVC 2005遇到了麻烦,但仅限于CE盒子。不是Win32交叉编译。

4 个答案:

答案 0 :(得分:6)

您的代码应该可以正常运行。还有其他错误,我们无法从这个测试用例中检测到。也许通过valgrind运行你的可执行文件来搜索内存错误。

答案 1 :(得分:1)

嗯,代码没有任何问题(正如我所解释的那样)。它不是最优的,肯定不是The Right Way (R),你应该像villentehaspam建议的那样修改你的代码。就像现在一样,你的代码会复制字符串m_value,因为你按值返回,这不如只返回一个const引用。

如果您提供显示问题的完整代码示例,我可以帮助您更好。

答案 2 :(得分:0)

并不重要但是该类中的std :: string返回可以使用const其他方面你只是创建一个成员值的副本,这是一种浪费。

std::string value() const { return m_value; }

答案 3 :(得分:-1)

以下是您撰写时通常会发生的事情:

printf("value: %s\n", v1.value().c_str());
  1. 编译器使临时std::string保留从v1.value()返回的值。
  2. 它调用v1.value()并将其返回值放在临时字符串中(具体如何改变它:通常它会将对临时的引用传递给方法的隐藏参数。请参阅{{3}讨论)。
  3. 它会在临时.c_str()上调用std::string,它会在某处隐藏const char *结果(例如注册)。
  4. 现在已经完成了临时std::string,因此将其销毁(即调用其析构函数,可能会释放一些堆栈空间)。
  5. 它将步骤(3)中获得的const char *指针作为printf()的参数传递。
  6. 问题是第3步中的指针指向临时std::string分配的内存,当调用临时析构函数时,它会被释放。到printf()使用时,这段记忆可能会很久没有了。

    基本上,任何类似于您所显示的用法都是危险的,应该避免使用。使用以下内容是正确的:

    std::string copiedString = v1.value();
    printf("value: %s\n", copiedString.c_str());
    

    因为copiedString的析构函数在copiedString超出范围之后才被调用,printf()返回后的某个时间。实际上,这并不比v1.value().c_str()效率低,因为在任何一种情况下都会创建一个临时的std::string

    返回对字符串的引用是一个很好的选择,只要调用者需要它,引用仍然有效。因此,对长期存在的对象中的成员变量的引用是可以的;对某些事物的提及结果是暂时的不是。