在C ++ 11中,std::function
是 MoveConstructible ,即可以在这些对象上有意义地调用std::move
或将它们存储在可移动类型中。一个窘境:下面的代码应该打印什么?
#include <stdio.h>
#include <functional>
#include <utility>
struct Big {
char data[1024];
};
int main(int argc, char **argv) {
Big blob;
// This bind will trigger small object optimization
std::function<void()> little = std::bind([]() { printf("little\n"); });
// This bind will not
std::function<void()> big = std::bind([](Big const& b) {
printf("big %c\n", b.data[0]);
}, blob);
auto little_moved = std::move(little);
auto big_moved = std::move(big);
// After move, one expects the source std::function to be empty
// (boolean value false)
printf("Little empty: %d\n", !little);
printf("Little (moved) empty: %d\n", !little_moved);
printf("Big empty: %d\n", !big);
printf("Big (moved) empty: %d\n", !big_moved);
return 0;
}
使用GCC 4.8编译,你得到这个:
linux-dev:nater:/tmp$ g++-4.8 -g -o foo move_function.cc -std=c++11
linux-dev:nater:/tmp$ ./foo
Little empty: 1
Little (moved) empty: 0
Big empty: 1
Big (moved) empty: 0
对象的行为与预期一致,使移动分配的RHS无效。但是,使用clang(Apple LLVM 6.0版)并不是那么清楚:
workbrick:nater:/tmp$ clang++ -g -o foo move_function.cc -std=c++11 -stdlib=libc++
workbrick:nater:/tmp$ ./foo
Little empty: 0
Little (moved) empty: 0
Big empty: 1
Big (moved) empty: 0
这里,当绑定参数很大时,RHS在移动后失效(在布尔上下文中为假),但是当绑定参数很小(技术上,不存在)时则不然。检查Xcode附带的<functional>
的实现,我们发现行为会有所不同,具体取决于是否已应用小对象优化:
template<class _Rp, class ..._ArgTypes>
template <class _Alloc>
function<_Rp(_ArgTypes...)>::function(allocator_arg_t, const _Alloc&,
function&& __f)
{
if (__f.__f_ == 0)
__f_ = 0;
else if (__f.__f_ == (__base*)&__f.__buf_)
{
// [nater] in this optimization, __f.__f_ is not invalidate
__f_ = (__base*)&__buf_;
__f.__f_->__clone(__f_);
}
else
{
// [nater] here, the RHS gets invalidated
__f_ = __f.__f_;
__f.__f_ = 0;
}
}
现在,我知道移动分配后RHS的状态是特定于类型的,但我感到惊讶这个STL类的行为不一致。这在规范中是否真的未定义?
答案 0 :(得分:1)
在dyp的helpful comment看起来很震惊,!func
(或者对象上的任何其他移动)之后auto foo = std::move(func)
是否为真,确实是未定义的行为。 C ++ 11规范中的相关文本:
(6)效果:如果!f,*这没有目标;否则,移动 - 将f的目标构造到* this的目标中,使f处于具有未指定值的有效状态
未定义未指定行为的另一个胜利。
答案 1 :(得分:0)
未指定对象移动后的值。
当然,除了它是一些有效的价值之外。
有一些常见的情况: