简体   繁体   English

作为参数传递的std :: string的生命周期

[英]lifetime of std::string passed as argument

I want to be sure I understand correctly. 我想确定我理解正确。 In the c++ functions below three instances of std::string will be created: 在下面的c ++函数中,将创建三个std :: string实例:

  • one for s1 in caller() via what I believe is called the assignment constructor 通过我认为称为赋值构造函数的调用者()中的s1
  • one for the s2 parameter of the callee() function via it's copy constructor 一个用于callee()函数的s2参数,通过它的复制构造函数
  • one for s3 via its copy constructor 一个用于s3通过其复制构造函数

Am I correct? 我对么? And if so will all three instances be cleaned up as they go out of scope? 如果是这样,所有三个实例都会在超出范围时被清理干净? I'm not really asking if this is good code or not, just if my understanding is correct. 我不是在问这个代码是不是很好,只要我的理解是正确的。

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

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

Don't assume copies are made everywhere they seem to be made. 不要假设副本是在他们似乎制作的任何地方制作的。 In practice, copy-elision occurs more often than you'd think. 在实践中,复制省略的发生频率超出了您的想象。 Compilers are free to optimize away extra copies, even if the copy has a side-effect: 编译器可以自由地优化掉额外的副本,即使副本有副作用:

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;
}

Moreover, if the methods are inline and the compiler detects no side-effects occur, the strings might not even be created. 此外,如果方法是内联的并且编译器检测不到发生任何副作用,则甚至可能不会创建字符串。

You are almost correct. 你几乎是对的。

Either three or four strings may be created (depending on whether the construction of s1 is elided), and in each case a constructor is called to construct them. 可以创建三个或四个字符串(取决于是否省略了s1的构造),并且在每种情况下都调用构造函数来构造它们。 Despite appearances, there are no calls to any assignment operators. 尽管出现了,但没有任何调用操作员的调用。

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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM