c++ - 为什么我们不能使用 move 语义只适用于 pass-by-value 而不是 const lvalue 引用?
问题描述
这是我用作参考的文章,最终在此 SO answer中提到。
作者举了两个例子:
示例 1:
std::vector<std::string>
sorted(std::vector<std::string> names)
{
std::sort(names);
return names;
}
// names is an lvalue; a copy is required so we don't modify names
std::vector<std::string> sorted_names1 = sorted( names );
// get_names() is an rvalue expression; we can omit the copy!
std::vector<std::string> sorted_names2 = sorted( get_names() );
示例 2:
std::vector<std::string>
sorted2(std::vector<std::string> const& names) // names passed by reference
{
std::vector<std::string> r(names); // and explicitly copied
std::sort(r);
return r;
}
然后说:
尽管 sorted 和 sorted2 乍一看似乎是相同的,但如果编译器确实进行了复制省略,则可能存在巨大的性能差异。即使 sorted2 的实际参数是一个右值,副本的来源 names 也是一个左值,所以副本不能被优化掉。从某种意义上说,复制省略是分离编译模型的牺牲品:在 sorted2 的主体内部,没有关于函数的实际参数是否为右值的信息;在外面,在呼叫现场,没有迹象表明最终会制作一份论据的副本。
我的问题很简单:为什么编译器不能在第二个示例中使用复制省略,但它可以在第一个示例中使用?
值传递和引用如何区分它们?names
在两个实例中都被命名,所以我假设我们也在两个实例中创建了一个左值。
解决方案
不同之处在于names
可修改对象与否。const 左值引用不可修改。
由于 get_names() 是一个右值,我们可以使用移动语义。
不总是。考虑何时调用移动构造函数。
但是,如果参数是 const 左值引用,那么我们必须将值“保留”为左值,因此不能发生简单的指针切换
当参数为左值引用时,可以修改对象。但是,您不能传递右值。
std::vector<std::string>
sorted3(std::vector<std::string>& names)
{
std::sort(names);
return names;
}
// names is an lvalue; lvalue reference can bind lvalue. argument will be modified after execution `sorted3`.
std::vector<std::string> sorted_names1 = sorted3( names );
// get_names() is an rvalue expression; we cannot bind by lvalue reference.
//std::vector<std::string> sorted_names2 = sorted3( get_names() );
const 左值引用可以绑定右值。但是,您不能修改该对象,从而不能发生简单的指针切换。
推荐阅读
- react-native - 在 ReactNative 中使用 Modal 上的自定义值初始化状态的最佳方法是什么?
- excel - CRM 365 工作流程和从 Excel 导入数据文件
- java - 使用 selenium WebDriver 提取文本和 Web 链接
- python - 使用 for 循环向字符串添加新行
- swift - SwiftUI - 在协议中返回不透明类型
- python - 无法选择 CSS 选择器
- maven - ClassNotFoundException:ContextLoaderListener,当使用带有 maven tomcat8 插件和 PostResources 的 Intellij
- javascript - 如何使用插值在 d3 v4 中实现发散色阶?
- android - WebViewClient.onRenderProcessGone() 未在首先崩溃 WebView 时调用
- python - 尽管图像是二进制 opencv,但 findContours() 不起作用