C++ 作为参数传递的std::字符串的生存期
我想确保我理解正确。在C++函数下面的三个实例 将创建std::string:C++ 作为参数传递的std::字符串的生存期,c++,stl,C++,Stl,我想确保我理解正确。在C++函数下面的三个实例 将创建std::string: 调用方()中的s1通过我认为称为赋值构造函数的 一个用于调用方()函数的s2参数,通过其复制构造函数 一个用于s3,通过其复制构造函数 我说得对吗?如果是这样,当这三个实例超出范围时,它们会被清理掉吗?我并不是问这是不是好代码,只是问我的理解是否正确 void caller(void) { std::string s1 = "hi"; callee(s1); } void callee(std:
- 调用方()中的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我不是说它会,而是说它可能,而且很可能。据我所知,没有“赋值构造函数”这样的东西。您有一个“转换构造函数”,它可以从一种类型转换为另一种类型。