我试图了解 C++17 标准保证的生命周期,特别是保证复制省略。 让我们从一个例子开始
std::string make_tmp();
std::string foo() {
return std::string{make_tmp().c_str()};
}
我对正在发生的事情的理解:
make_tmp
创建一个临时的 string
我们将调用 t
; foo
返回一个(不必要创建的)临时(t
的 c_str
的拷贝)。
标准(甚至是 C++17 之前的版本)保证 t
的生命周期是计算完整返回表达式之前的时间。
因此,创建 t
的临时拷贝(将被返回)是安全的。
现在copy elisions开始;更具体地说,第一个 C++17 block 中的第二个项目符号:
In a function call, if the operand of a return statement is a prvalue and the return type of the function is the same as the type of that prvalue.
因此根本不会创建临时拷贝。
后续问题:
返回的临时拷贝是否仍然意味着
t
的生命周期足够长——即使它保证被删除?考虑下面给出的
foo
的变体。 我假设不再需要复制省略(但很有可能)。 如果拷贝不会被删除,那么标准就已经涵盖了我们(通过上面的论点)。 如果拷贝被省略,尽管return
ed 表达式的类型与foo
不同,标准是否仍然保证t
的足够生命周期> 的返回类型?
foo
-变体:
std::string foo() {
return make_tmp().c_str();
}
我想了解标准中纯粹隐含的保证。
请注意,我知道这两个 foo
版本都“有效”(即,即使在各种编译器下使用自定义类进行测试时也不涉及悬空指针)。
最佳答案
我认为这里有一些关于哪些拷贝被删除的混淆。让我们从最远的角度来看:
std::string make_tmp();
std::string foo() {
return std::string{make_tmp().c_str()};
}
std::string s = foo();
在这里,可能创建了四个 std::string
:make_tmp()
,临时的 std::string {...}
从它构造,foo()
的返回对象,和 s
。这意味着三个拷贝(我只是为了保持一致性而使用拷贝这个词,即使所有这些都是移动。希望这不会造成混淆)。
复制省略允许删除其中两个拷贝:
- 从
std::string{...}
复制到foo()
的返回对象。 - 从
foo()
复制到s
这两种省略在 C++17 的“保证复制省略”中都是强制要求的——因为我们是从纯右值(这个术语有点令人困惑,因为我们实际上并没有执行重载决议来确定我们需要执行复制构造然后跳过它,我们只是直接初始化)。代码等同于:
std::string s{make_tmp().c_str()};
虽然这不能被删除 - 我们仍然通过 make_tmp()
构造一个 string
,提取它的内容,然后构造一个新的 string
来自他们。没办法。
提供的变体具有完全相同的行为。
关于c++ - 返回临时人员的复制省略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50528969/