确保移动构造函数被调用
Making sure move constructor gets called
我有以下简化的代码示例:
#include <algorithm>
#include <iostream>
using namespace std;
class ShouldBeMovedWhenSwapped
{
public:
// ShouldBeMovedWhenSwapped() = default;
// ShouldBeMovedWhenSwapped(ShouldBeMovedWhenSwapped&&) = default;
// ShouldBeMovedWhenSwapped(const ShouldBeMovedWhenSwapped&) = default;
// ShouldBeMovedWhenSwapped& operator=(ShouldBeMovedWhenSwapped&&) = default;
struct MoveTester
{
MoveTester() {}
MoveTester(const MoveTester&) { cout << "tester copied " << endl; }
MoveTester(MoveTester&&) { cout << "tester moved " << endl; }
MoveTester& operator=(MoveTester) { cout << "tester emplaced" << endl; return *this; } // must be declared if move declared
};
MoveTester tester;
};
int main()
{
ShouldBeMovedWhenSwapped a;
ShouldBeMovedWhenSwapped b;
std::swap(a,b);
return 0;
}
我正在使用 MinGW,而 运行 'gcc --version' 我得到 gcc 4.7.2
编辑:
对于第一个问题,请参阅问题中的评论。它似乎是 gcc 中的错误。
代码的输出取决于哪些构造函数被注释掉了。但我不明白为什么会出现差异。 每个输出背后的原因是什么?
// Everything commented out
tester moved
tester copied <---- why not moved?
tester emplaced
tester copied <---- why not moved?
tester emplaced
// Nothing commented out
tester moved
tester moved
tester emplaced
tester moved
tester emplaced
// Move constructor commented out
tester copied
tester moved
tester emplaced
tester moved
tester emplaced
关于我的第二个问题(这就是我开始这个测试的原因)- 假设我有一个大向量的真实案例而不是 class MoveTester,我怎么能确定在这种情况下矢量被移动而不是被复制?
问题的第一部分是过时的编译器,但还有另一个问题:您以次优方式声明 MoveTester::operator=
- 它按值获取参数,因此调用了 copy/move 构造函数额外的时间。试试这个版本的 MoveTester
:
struct MoveTester
{
MoveTester() {}
MoveTester(const MoveTester&) { cout << "tester copied " << endl; }
MoveTester(MoveTester&&) { cout << "tester moved " << endl; }
MoveTester& operator=(const MoveTester&) { cout << "tester copy assignment" << endl; return *this; } // must be declared if move declared
MoveTester& operator=(MoveTester&&) { cout << "tester move assignment" << endl; return *this; } // must be declared if move declared
};
我得到 the following output:
tester moved
tester move assignment
tester move assignment
也许即使使用 GCC 4.7,您也会得到类似的东西。
关于你的第二个问题,std::vector
的移动构造函数由标准保证具有恒定的时间复杂度。问题是编译器是否遵守标准。我相信唯一可以确保的方法是调试或分析您的代码。
我有以下简化的代码示例:
#include <algorithm>
#include <iostream>
using namespace std;
class ShouldBeMovedWhenSwapped
{
public:
// ShouldBeMovedWhenSwapped() = default;
// ShouldBeMovedWhenSwapped(ShouldBeMovedWhenSwapped&&) = default;
// ShouldBeMovedWhenSwapped(const ShouldBeMovedWhenSwapped&) = default;
// ShouldBeMovedWhenSwapped& operator=(ShouldBeMovedWhenSwapped&&) = default;
struct MoveTester
{
MoveTester() {}
MoveTester(const MoveTester&) { cout << "tester copied " << endl; }
MoveTester(MoveTester&&) { cout << "tester moved " << endl; }
MoveTester& operator=(MoveTester) { cout << "tester emplaced" << endl; return *this; } // must be declared if move declared
};
MoveTester tester;
};
int main()
{
ShouldBeMovedWhenSwapped a;
ShouldBeMovedWhenSwapped b;
std::swap(a,b);
return 0;
}
我正在使用 MinGW,而 运行 'gcc --version' 我得到 gcc 4.7.2
编辑: 对于第一个问题,请参阅问题中的评论。它似乎是 gcc 中的错误。
代码的输出取决于哪些构造函数被注释掉了。但我不明白为什么会出现差异。 每个输出背后的原因是什么?
// Everything commented out
tester moved
tester copied <---- why not moved?
tester emplaced
tester copied <---- why not moved?
tester emplaced
// Nothing commented out
tester moved
tester moved
tester emplaced
tester moved
tester emplaced
// Move constructor commented out
tester copied
tester moved
tester emplaced
tester moved
tester emplaced
关于我的第二个问题(这就是我开始这个测试的原因)- 假设我有一个大向量的真实案例而不是 class MoveTester,我怎么能确定在这种情况下矢量被移动而不是被复制?
问题的第一部分是过时的编译器,但还有另一个问题:您以次优方式声明 MoveTester::operator=
- 它按值获取参数,因此调用了 copy/move 构造函数额外的时间。试试这个版本的 MoveTester
:
struct MoveTester
{
MoveTester() {}
MoveTester(const MoveTester&) { cout << "tester copied " << endl; }
MoveTester(MoveTester&&) { cout << "tester moved " << endl; }
MoveTester& operator=(const MoveTester&) { cout << "tester copy assignment" << endl; return *this; } // must be declared if move declared
MoveTester& operator=(MoveTester&&) { cout << "tester move assignment" << endl; return *this; } // must be declared if move declared
};
我得到 the following output:
tester moved
tester move assignment
tester move assignment
也许即使使用 GCC 4.7,您也会得到类似的东西。
关于你的第二个问题,std::vector
的移动构造函数由标准保证具有恒定的时间复杂度。问题是编译器是否遵守标准。我相信唯一可以确保的方法是调试或分析您的代码。