我有课Foo
class Foo {
public:
Foo(std::string s) : s_(std::move(s)) {
std::cout << "Constructor " << s_ << "\n";
}
Foo(const Foo& other) {
s_ = other.s_;
std::cout << "Copy Contructor\n";
}
Foo& operator=(const Foo& other) {
std::cout << "Copy assignment\n";
s_ = other.s_;
return *this;
}
Foo(Foo&& other) {
s_ = std::move(other.s_);
std::cout << "Move Contructor\n";
}
Foo& operator=(Foo&& other) {
std::cout << "Move assignment\n";
s_ = std::move(other.s_);
return *this;
}
void Set(std::string s) {
s_ = std::move(s);
}
const std::string& Get() const {
return s_;
}
private:
std::string s_;
};
按预期发生复制省略的正常情况:
Foo DoSomething(std::string s) {
Foo foo{std::move(s)};
if (foo.Get() == "2") {
return foo;
}
if (foo.Get() == "4") {
return foo;
}
foo.Set("1");
return foo;
}
int main()
{
Foo ret(DoSomething("5"));
}
我正在尝试理解这些案例:
案例1
Foo DoSomething(std::string s) {
Foo foo{std::move(s)};
if (foo.Get() == "2") {
return foo;
}
if (foo.Get() == "4") {
return Foo("4");
}
foo.Set("1");
return foo;
}
int main()
{
Foo ret(DoSomething("5"));
}
调用移动构造函数,即不会发生复制省略
案例2
Foo DoSomething(std::string s) {
if (s == "2") {
return Foo("2");
}
if (s == "4") {
return Foo("4");
}
Foo foo{std::move(s)};
foo.Set("1");
return foo;
}
int main()
{
Foo ret(DoSomething("5"));
}
复制省略再次起作用。
案例3
Foo DoSomething(std::string s) {
Foo foo1{"2"};
Foo foo2{"4"};
if (s == "2") {
return foo1;
}
if (s == "4") {
return foo2;
}
Foo foo{std::move(s)};
return foo;
}
int main()
{
Foo ret(DoSomething("4"));
}
不会发生复制省略。
案例4
Foo DoSomething(std::string s) {
Foo foo1{"2"};
Foo foo2{"4"};
if (s == "2") {
return foo1;
}
if (s == "4") {
return foo2;
}
Foo foo{std::move(s)};
return foo;
}
int main()
{
Foo ret(DoSomething("5"));
}
再次发生复制省略。
我使用 C++20 编译器运行这些示例。我知道 C++17 只保证 RVO 而不是 NRVO,但我现在很困惑,不知道何时可以在实践中实现复制省略。
但我现在很困惑,不知道什么时候可以在实践中实现复制省略。
您不应该做出任何假设。 NRVO 的应用情况因编译器而异,有时只是由于一些看似不相关的实现细节而以意想不到的方式出现(例如,如果使用
auto
返回类型声明函数,Clang 有时会表现不同)。