首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++移动构造函数过时了吗?

C++移动构造函数过时了吗?
EN

Stack Overflow用户
提问于 2018-08-22 03:14:44
回答 1查看 483关注 0票数 4

我编写了自己的字符串类型(Str)来演示基本构造函数、析构函数和赋值操作符;除了移动构造函数之外,我还可以看到它们都在C++17中执行。

显然,由于返回值优化(RVO),移动构造函数不再被大量使用。

是否只有在显式调用std::move时才调用move构造函数?

还能叫什么时候呢?

它是不是因为RVO而被淘汰了?

这是我的Str类型:

代码语言:javascript
复制
struct Str {
  Str(): p(nullptr) {}
  Str(const char* s) { cout << "cvctor \"" << s << "\"\n"; copy(s); }
  Str(const Str& s): p(nullptr) { cout << "cpctor deep\""<<s.p<<"\"\n"; copy(s.p); }
  Str( Str&& s) { cout << "mvctr shallow \"" << s.p << "\"\n"; p = s.p; s.p=nullptr; }
  const Str& operator=(const Str& s) { cout << "op=\""<<s.p<<"\"\n"; copy(s.p); return *this; }
  const Str& operator=( Str&& s) { cout << "op= shallow \""<<s.p<<"\"\n"; p=s.p; s.p=nullptr; return *this; }
  ~Str(){ if ( p != nullptr ) { cout << "dtor \"" << p << "\"\n"; delete [] p; } }

private:
  char* p = nullptr;
  char* copy(const char* s)
};
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-08-22 03:29:57

不,一点也不

返回值优化并不是使用移动构造函数的唯一点。每次您想要从rvalue构造某种类型的值时,都会使用移动构造函数。

你基本上是一个人问两个问题。我们先从

是否仅响应显式调用std::move调用了move构造函数?

move构造函数和std::move是切分相关的,但本质上是非常独立的。每次从相同类型的rvalue初始化变量时,都会调用移动构造函数。另一方面,std::move使显式地从所谓的lvalue获取到这样的rvalue成为可能,但这不是唯一的方法。

代码语言:javascript
复制
template<typename T>
void foo(T&& value) { // A so-called universal reference
    T other_value = std::forward<T>(value);
}
foo( string{"some string"} ); // other_value is move initialized

你看,std::forward是另一种获得rvalue的方法。实际上,"some string"还会在上面的代码中生成一个const char*类型的rvalue

是时候休息一下了。如果您听到rvalue,您可能会想到&&,它是一个rvalue-reference。这是微妙的不同。问题是,给任何东西取一个名字都会使它成为lvalue。因此,下面的代码:

代码语言:javascript
复制
foo(string&& value) {
    T other_value = value;
}
foo( "some_string" ); // other_value is STILL copy initialized

foo(string&& value) {
    T other_value = std::move(value);
}
foo( "some_string" ); // other_value is now properly move initialized

正确的看待&&的方法是这样的引用可以用rvalue初始化,但是它本身并不总是这样的rvalue。有关更多信息,请参见here

它是不是因为RVO而被淘汰了?

这里有两个显著的例子,其中移动构造函数在RVO之外经常被显著使用。

  • 移到方法参数 void (字符串值);//其他字符串& some_string = get_me_a_string();foo( ::std:: move ( some_string ) );//使用move构造函数初始化值some_string.clear();//很可能是没有操作/这样做会留下空的some_string。 请注意,在上面的示例中,some_string是一个引用这一事实与是否使用移动构造无关。这是一个参考,表明RVO可能并不总是可能的。在这种情况下,在some_string被移出之后,将处于一个未指定但有效的状态,这是一种奇特的方式,可以说不会发生未定义的行为,而且引用仍然有效。
  • 进入田野 类FooBar { string fooField;//Constructor FooBar( string bar ):fooField( ::std:: move (bar) ) //使用移动构造函数初始化fooField {}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51959379

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档