8

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

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 可以使用它之前从内存中消失了。有时它会打印 value: hello 其他时候它会崩溃或什么也不打印。

如果我首先像这样复制字符串

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

事情确实有效。

当然,必须有一种方法可以避免使用临时字符串执行此操作。

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

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

4

4 回答 4

6

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

于 2011-01-06T22:25:51.043 回答
1

Well, there's nothing wrong with the code (as I interpret it). It is not optimal and surely not The Right Way (R), you should modify your code like villentehaspam suggests. As it is now, your code makes a copy of the string m_value because you return by value, which is not as good as only returning a const reference.

If you provide a complete code sample that shows the problem, I could help you better.

于 2011-01-06T22:18:25.800 回答
0

这并不重要,但该类中的 std::string 返回可以使用 const ,否则明智的做法是创建成员值的副本,这是一种浪费。

std::string value() const { return m_value; }
于 2011-01-07T17:02:26.267 回答
-1

以下是您编写时通常发生的情况:

printf("value: %s\n", v1.value().c_str());
  1. 编译器临时std::string保存从v1.value().
  2. 它调用v1.value()并将其返回值放入临时字符串中(它的具体执行方式可能会有所不同:通常它将对临时的引用作为隐藏参数传递给方法。参见http://en.wikipedia.org/wiki/ Return_value_optimization供讨论)。
  3. 它调用.c_str()临时的std::string,它将const char *结果存储在某个地方(例如寄存器)。
  4. 它现在已经完成了临时的std::string,所以销毁它(即调用它的析构函数,可能会释放一些堆栈空间)。
  5. 它将const char *在步骤 (3) 中获得的指针作为参数传递给printf().

问题是步骤 3 中的指针指向由临时分配的内存std::string,当调用临时的析构函数时,该内存被释放。当它被使用时,这个内存可能早就消失了printf()

基本上,任何像你展示的那样的用法都是危险的,应该避免。使用以下是正确的:

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

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

返回对字符串的引用是一个很好的选择,只要该引用在调用者需要时保持有效。因此,对长寿命对象中的成员变量的引用是可以的;对事实证明是临时的东西的引用不是。

于 2014-04-22T14:03:32.853 回答