编译器是否优化了默认移动构造函数?
Is default move constructor optimized away by compiler?
我有一个 std::multimap 类型如下:
typedef std::multimap<std::pair<bool,uint32_t>, FooObject>
FooObject 声明了默认移动复制和赋值构造函数:
FooObject(FooObject&& v) = default;
FooObject& operator=(FooObject&& other)=default;
copy/assign 构造函数是私有的,以禁用隐式复制。
所以我应该能够像这样在地图中放置一对:
mymap.emplace(std::make_pair(false,32),FooObject());
这会抛出一个错误列表,最后一个是:
error C2660: 'std::pair::pair': function does not take
2 arguments
如果我在没有 "default" 的情况下声明移动复制分配构造函数
然后编译就ok了。
FooObject(FooObject&& v){}
FooObject& operator=(FooObject&& other){}
这是为什么?当用 "default" 关键字标记时,编译器是否优化掉这些构造函数?我正在使用 MSVC140
更新:
根据下面的评论我找到了原因 - FooObject 有一个不可复制的成员实例。
这是 FooObject:
#define NO_COPY_ASSIGN(TypeName) \
TypeName (const TypeName &); \
void operator= (const TypeName &);
class FooObject
{
private:
NO_COPY_ASSIGN(FooObject)
public:
struct FooStruct
{
FooBuffer frameBuffer; //<--Here it is
}fooStruct;
FooObject(){}
/** Move constructor to allow insert into vector without copy */
FooObject(FooObject&& v) = default;
FooObject& operator=(FooObject&& other) = default;
};
*FooBuffer 也有它的 copy/assign private.But 我仍然不明白为什么用 {} 替换 'default' 修复 that.Please 解释。
您的问题是 FooObject
的成员之一不可移动,这会阻止编译器生成默认移动操作。
您自己实现的 {}
版本的移动操作 对 FooObject
因此是合法的。
两者的区别
FooObject(FooObject&& v) = default;
和
FooObject(FooObject&& v){}
是前者会发出一个构造函数,从 v
移动每个成员,而后者默认构造每个成员并且对 v
.
不执行任何操作
由于 FooBuffer
不可移动,这意味着编译器将删除 FooObject(FooObject&& v) = default;
,因为它的格式不正确。
使用 FooObject(FooObject&& v){}
就没有这个问题,因为您从不尝试移动 v
的成员。由于没有成员初始化列表,编译器会为您添加一个默认构造成员的列表。
您可以通过以下方式更明确地看到此行为:
struct Moveable
{
Moveable() = default;
Moveable(Moveable&&) { std::cout << "in Moveable(Moveable&&)\n"; }
};
struct Foo
{
Foo() = default;
Foo(Foo&&) = default;
Moveable m;
};
struct Bar
{
Bar() = default;
Bar(Bar&&){}
Moveable m;
};
int main()
{
Foo f;
Bar b;
std::cout << "test_f\n";
Foo test_f(std::move(f));
std::cout << "test_b\n";
Bar test_b(std::move(b));
}
输出
test_f
in Moveable(Moveable&&)
test_b
表明在 Bar
的移动构造函数中实际上没有移动任何东西。
我有一个 std::multimap 类型如下:
typedef std::multimap<std::pair<bool,uint32_t>, FooObject>
FooObject 声明了默认移动复制和赋值构造函数:
FooObject(FooObject&& v) = default;
FooObject& operator=(FooObject&& other)=default;
copy/assign 构造函数是私有的,以禁用隐式复制。
所以我应该能够像这样在地图中放置一对:
mymap.emplace(std::make_pair(false,32),FooObject());
这会抛出一个错误列表,最后一个是:
error C2660: 'std::pair::pair': function does not take 2 arguments
如果我在没有 "default" 的情况下声明移动复制分配构造函数 然后编译就ok了。
FooObject(FooObject&& v){}
FooObject& operator=(FooObject&& other){}
这是为什么?当用 "default" 关键字标记时,编译器是否优化掉这些构造函数?我正在使用 MSVC140
更新:
根据下面的评论我找到了原因 - FooObject 有一个不可复制的成员实例。 这是 FooObject:
#define NO_COPY_ASSIGN(TypeName) \
TypeName (const TypeName &); \
void operator= (const TypeName &);
class FooObject
{
private:
NO_COPY_ASSIGN(FooObject)
public:
struct FooStruct
{
FooBuffer frameBuffer; //<--Here it is
}fooStruct;
FooObject(){}
/** Move constructor to allow insert into vector without copy */
FooObject(FooObject&& v) = default;
FooObject& operator=(FooObject&& other) = default;
};
*FooBuffer 也有它的 copy/assign private.But 我仍然不明白为什么用 {} 替换 'default' 修复 that.Please 解释。
您的问题是 FooObject
的成员之一不可移动,这会阻止编译器生成默认移动操作。
您自己实现的 {}
版本的移动操作 对 FooObject
因此是合法的。
两者的区别
FooObject(FooObject&& v) = default;
和
FooObject(FooObject&& v){}
是前者会发出一个构造函数,从 v
移动每个成员,而后者默认构造每个成员并且对 v
.
由于 FooBuffer
不可移动,这意味着编译器将删除 FooObject(FooObject&& v) = default;
,因为它的格式不正确。
使用 FooObject(FooObject&& v){}
就没有这个问题,因为您从不尝试移动 v
的成员。由于没有成员初始化列表,编译器会为您添加一个默认构造成员的列表。
您可以通过以下方式更明确地看到此行为:
struct Moveable
{
Moveable() = default;
Moveable(Moveable&&) { std::cout << "in Moveable(Moveable&&)\n"; }
};
struct Foo
{
Foo() = default;
Foo(Foo&&) = default;
Moveable m;
};
struct Bar
{
Bar() = default;
Bar(Bar&&){}
Moveable m;
};
int main()
{
Foo f;
Bar b;
std::cout << "test_f\n";
Foo test_f(std::move(f));
std::cout << "test_b\n";
Bar test_b(std::move(b));
}
输出
test_f
in Moveable(Moveable&&)
test_b
表明在 Bar
的移动构造函数中实际上没有移动任何东西。