C++ 作为参数传递的std::字符串的生存期

C++ 作为参数传递的std::字符串的生存期,c++,stl,C++,Stl,我想确保我理解正确。在C++函数下面的三个实例 将创建std::string: 调用方()中的s1通过我认为称为赋值构造函数的 一个用于调用方()函数的s2参数,通过其复制构造函数 一个用于s3,通过其复制构造函数 我说得对吗?如果是这样,当这三个实例超出范围时,它们会被清理掉吗?我并不是问这是不是好代码,只是问我的理解是否正确 void caller(void) { std::string s1 = "hi"; callee(s1); } void callee(std:

我想确保我理解正确。在C++函数下面的三个实例 将创建std::string:

  • 调用方()中的s1通过我认为称为赋值构造函数的
  • 一个用于调用方()函数的s2参数,通过其复制构造函数
  • 一个用于s3,通过其复制构造函数
我说得对吗?如果是这样,当这三个实例超出范围时,它们会被清理掉吗?我并不是问这是不是好代码,只是问我的理解是否正确

void caller(void) {
    std::string s1 = "hi";
    callee(s1);
}

void callee(std::string s2) {
    std::string s3 = s2;
}

不要假设复制品似乎在任何地方都可以复制。在实践中,复制省略的发生频率比您想象的要高。编译器可以自由优化多余的拷贝,即使拷贝有副作用:

void caller(void) {
    std::string s1 = "hi";
    //theoretically, s1 is copied here
    //in practice, the compiler will optimize the call away
    functionCallee(s1);
}

void callee(std::string s2) {
    //although s2 is passed by value, it's probably no copy was created
    //most likely, it's exactly the same as s1 from the calling context
    std::string s3 = s2;
}

此外,如果这些方法是内联的,并且编译器检测到没有出现任何副作用,那么这些字符串甚至可能无法创建。

您几乎是正确的

可以创建三个或四个字符串(取决于是否省略了
s1
的构造),并且在每种情况下都会调用构造函数来构造它们。尽管出现,但没有调用任何赋值运算符

void caller(void) {
    //A temporary std::string is constructed with the
    //basic_string(const CharT* s, const Allocator& alloc = Allocator())
    //constructor.
    //(In the call, `s` is initialized to point to the first element of "hi".)
    //This temporary is then move constructed in to s1.
    //The move constructor is
    //basic_string(basic_string&& other)
    //This move construction may be elided.
    std::string s1 = "hi"; //At the end of the full expression (ie, at the semicolon)
                           //the lifetime of the temporary string ends (unless
                           //the construction of s1 is elided, in which
                           //case the temporary becomes s1, and its lifetime ends
                           //with s1).
    //s2 is copy constructed from s1
    //The copy constructor is
    //basic_string(const basic_string& other)
    callee(s1);
    //the lifetime of s1 ends
}

void callee(std::string s2) {
    //s3 is copy constructed from s2
    std::string s3 = s2;
    //the lifetime of s3 ends
    //the lifetime of s2 ends
}

谢谢所以,没有内存泄漏吗?按照我的说明进行操作?@JohnFitzpatrick如果您从不使用
new
malloc
,那么就不会有内存泄漏@Mankarse s2是按值传递的,因此理论上,在
被调用方
内创建一个副本。但可能不是这样。@LuchianGrigore:这并不能解释复制省略是如何应用的
caller
不知道
functionCallee
是否会修改参数。当然,
调用方
知道它将不再使用
s1
,因此它可能会删除副本。但是,只要再次使用参数,就可以很容易地停止复制省略。@Nicolas我不是说它会,而是说它可能,而且很可能。据我所知,没有“赋值构造函数”这样的东西。您有一个“转换构造函数”,它可以从一种类型转换为另一种类型。