编译器是否可以自动生成std::move用于最后一次使用左值
Can compiler generate std::move for a last use of lvalue automatically?
这样的代码经常出现在r值参考文章中:
Dave Abrams: Move It With右值引用
void g(X);
void f()
{
X b;
g(b); // still need the value of b
…
g( std::move(b) ); // all done with b now; grant permission to move
}
编译器是否可以自动生成这种优化,即检测l值无论如何都将被销毁并且可以从其中移动,或者这是否违反标准,假设编译器不知道如何为X类实现移动,复制或销毁?
如果这种优化是允许的,它是由一些编译器在实践中执行的吗?
No。考虑:
using X = std::shared_ptr<int>;
void g(X);
void f() {
X b = std::make_shared<int>();
int &i = *b;
g(b); // last use of 'b'
i = 5;
}
一般来说,编译器不能假设改变X
的拷贝、移动和析构函数的语义是合法的,而不对使用b
的所有代码(即整个f
、g
和其中使用的所有类型)进行分析。
事实上,在某些情况下,整个程序的分析可能是必要的:
using X = std::shared_ptr<std::lock_guard<std::mutex>>;
std::mutex i_mutex;
int i;
void g(X);
void f() {
X b = std::make_shared<std::lock_guard<std::mutex>>(i_mutex);
g(b); // last use of 'b'
i = 5;
}
b
,这将引入与其他使用i_mutex
同步访问i
的线程之间的数据竞争。编译器可以做到吗?只能作为显式语言扩展,因为标准不允许他们在没有显式语言扩展的情况下进行这种优化。
他们应该这样做吗?不。g(b)
的含义应以g
和b
的定义为基础。g
应该是某种可调用类型,它具有重载,该重载接受b
可以隐式转换为的内容。给定对所有可用g
s的定义和b
的定义的访问权,您应该能够准确地确定将调用什么函数。
允许这种"优化"现在意味着这是不可能的。g(b)
可能执行移动,也可能不执行移动,这取决于g(b)
恰好在函数中的位置。这可不是件好事。
return
被允许使用它,但只是因为它仍然具有相同的含义。
b
是一个生命周期限制在函数范围内的值类型,那么return b
将总是尝试从b
移出。(…)假设一个通用的情况下,编译器不知道任何关于如何移动,复制或销毁实现的X类?
不,编译器不允许基于信仰进行优化。
为清楚起见,这个问题与副本省略无关:编译器可以允许省略一个副本,但它们不能随意地将副本更改为移动。
相关文章:
- foor 循环的最后一次迭代中的指针更改
- 调用函数一次用于动态链接库,一次从可执行文件调用函数
- C++ 查找算法:如何找到元素的最后一次出现?
- X 变量在最后一次尝试简单猜谜游戏时发生变化,C++
- 仅当捕获组最后一次出现时,才使字符成为可选字符
- ffmpeg H264一次对帧进行编码,用于网络流传输
- C++ 向量元素被最后一次调用push_back替换
- C 在子字符串内找到字符串的最后一次出现
- 如何在boost::d ynamic_bitset中找到一个的第一次和最后一次出现<>
- 使用 std::unique 和 vector.erase 删除除最后一次出现的重复元素之外的所有元素
- 删除字符C++最后一次出现时字符数组的开头
- std::getline 在最后一次出现分隔符后跳过来自 std::cin 的输入,但不跳过来自 std::istrin
- 如何在最后一次EOL后删除文件的内容
- 如何在数组中查找特定值的第一次和最后一次出现
- 在线性搜索中查找int类型的最后一次出现
- 如何使用libgit2从git存储库中的HEAD获取最后一次提交
- 编译器是否可以自动生成std::move用于最后一次使用左值
- SQLite在最后一次引用共享行时删除该行
- 编译器是否在最后一次使用可移动对象时自动使用移动语义?
- 从文件中的特定位置查找文件中字符串的最后一次出现