当函数通过不同路径返回局部变量和临时变量时复制省略

问题描述 投票:0回答:1

我有课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,但我现在很困惑,不知道何时可以在实践中实现复制省略。

c++ c++17 copy-elision return-value-optimization
1个回答
0
投票

但我现在很困惑,不知道什么时候可以在实践中实现复制省略。

您不应该做出任何假设。 NRVO 的应用情况因编译器而异,有时只是由于一些看似不相关的实现细节而以意想不到的方式出现(例如,如果使用

auto
返回类型声明函数,Clang 有时会表现不同)。

© www.soinside.com 2019 - 2024. All rights reserved.