为什么在返回字符串的函数上调用std :: string.c_str()不起作用? [英] Why does calling std::string.c_str() on a function that returns a string not work?

查看:140
本文介绍了为什么在返回字符串的函数上调用std :: string.c_str()不起作用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

  std :: string getString(){
std :: string str (你好);
return str;
}

int main(){
const char * cStr = getString()。c_str();
std :: cout<< cStr < std :: endl; // this prints garbage
}

我认为会发生的是 getString()会返回一个 code>按值返回);因此, str 的副本将在 main()中保持活动,直到 main )返回。这将使 cStr 指向有效的内存位置:底层 char [] char由 getString()返回的 str 副本的保存在 main()



然而,这显然不是这样,所以,问题是,何时 str 销毁,为什么?

解决方案

blockquote>

getString()将返回一个str(getString()返回值的副本);


没错。

str的副本将在main()中保持活着直到main()返回。


否,返回的副本是临时的 std :: string ,它将在创建它的语句的结尾处被销毁,这意味着在 std :: cout < < cStr < std :: endl; 。这是为什么会打印出垃圾。



您可以将返回的值赋给一个命名的变量或一个const引用(临时的生命周期将被延长,直到引用出来范围)。如:

  std :: string s1 = getString(); // s1将从临时变量
复制初始化const char * cStr1 = s1.c_str();
std :: cout<< cStr1<< std :: endl; // safe

const std :: string& s2 = getString(); //临时变量的生命周期将被绑定到一个const引用时扩展
const char * cStr2 = s2.c_str();
std :: cout<< cStr2 < std :: endl; // safe



这里是来自[The.C ++。Programming.Language.Special.Edition] 10.4.10临时对象[class.temp]]:


除非绑定到引用或用于初始化命名对象,否则
临时对象在创建的
中的完整表达式的末尾被销毁。完整表达式是一个表达式,
不是其他表达式的子表达式。



标准字符串类有一个成员函数c_str b返回一个C样式的零终止字符数组(§3.5.1,§20.4.1)。此外,运算符+被定义为意味着字符串连接。
这些是非常有用的字符串设施。然而,它们组合起来会导致模糊的问题。
例如:

  void f(string& s1,string& s2,string& s3)
{

const char * cs =(s1 + s2).c_str();
cout<< cs;
if(strlen(cs =(s2 + s3).c_str())< 8& cs [0] =='a'){
// cs used here
}

}

可能你的第一反应是这样做,我同意。
然而,这样的代码确实是写的,所以值得知道它是如何
解释。



类字符串的临时对象被创建保持s1 + s2。
接下来,从该对象中提取指向C风格字符串的指针。然后
- 在表达式的末尾 - 临时对象被删除。现在,
其中是分配的C风格字符串?可能是作为保存s1 + s2的
临时对象的一部分,并且该存储不能保证
在临时被销毁之后存在。因此,cs将
指向释放分配的存储。输出操作cout < cs可能工作
按预期,但这将是绝对运气。编译器可以检测和
警告这个问题的许多变体。



I have the following code:

std::string getString() {
    std::string str("hello");
    return str;
}

int main() {
    const char* cStr = getString().c_str();
    std::cout << cStr << std::endl; // this prints garbage
}

What I thought would happen is that getString() would return a copy of str (getString() returns by value); thus, the copy of str would stay "alive" in main() until main() returns. This would make cStr point to a valid memory location: the underlying char[] or char* (or whatever) of the copy of str returned by getString() which, remains in main().

However, this is obviously not the case, as the program outputs garbage. So, the question is, when is str destroyed, and why?

解决方案

getString() would return a copy of str (getString() returns by value);

It's right.

thus, the copy of str would stay "alive" in main() until main() returns.

No, the returned copy is a temporary std::string, which will be destroyed at the end of the statement in which it was created, it means that before std::cout << cStr << std::endl;. That's why garbage was printed out.

You can assign the returned value to a named variable or a const reference (the lifetime of the temporary will be extended until the reference go out of scope). Such as:

std::string s1 = getString();    // s1 will be copy initialized from the temporary variable
const char* cStr1 = s1.c_str();
std::cout << cStr1 << std::endl; // safe

const std::string& s2 = getString(); // lifetime of temporary variable will be extended when bound to a const reference
const char* cStr2 = s2.c_str();
std::cout << cStr2 << std::endl; // safe

Here is an explanation from [The.C++.Programming.Language.Special.Edition] 10.4.10 Temporary Objects [class.temp]]:

Unless bound to a reference or used to initialize a named object, a temporary object is destroyed at the end of the full expression in which it was created. A full expression is an expression that is not a subexpression of some other expression.

The standard string class has a member function c_str() that returns a C-style, zero-terminated array of characters (§3.5.1, §20.4.1). Also, the operator + is defined to mean string concatenation. These are very useful facilities for strings . However, in combination they can cause obscure problems. For example:

void f(string& s1, string& s2, string& s3)
{

    const char* cs = (s1 + s2).c_str();
    cout << cs ;
    if (strlen(cs=(s2+s3).c_str())<8 && cs[0]==´a´) {
        // cs used here
    }

}

Probably, your first reaction is "but don’t do that," and I agree. However, such code does get written, so it is worth knowing how it is interpreted.

A temporary object of class string is created to hold s1 + s2 . Next, a pointer to a C-style string is extracted from that object. Then – at the end of the expression – the temporary object is deleted. Now, where was the C-style string allocated? Probably as part of the temporary object holding s1 + s2 , and that storage is not guaranteed to exist after that temporary is destroyed. Consequently, cs points to deallocated storage. The output operation cout << cs might work as expected, but that would be sheer luck. A compiler can detect and warn against many variants of this problem.

这篇关于为什么在返回字符串的函数上调用std :: string.c_str()不起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆