在C++ 11中,我们可以编写以下代码:
struct Cat {
Cat(){}
};
const Cat cat;
std::move(cat); //this is valid in C++11
Run Code Online (Sandbox Code Playgroud)
当我打电话时std::move,这意味着我想移动对象,即我将改变对象.移动const对象是不合理的,为什么不std::move限制这种行为呢?这将是未来的陷阱,对吧?
陷阱意味着布兰登在评论中提到:
"我认为他的意思是"偷偷摸摸"他鬼鬼祟祟偷偷摸摸,因为如果他没有意识到,他最终得到的副本并不是他想要的."
在Scott Meyers的"Effective Modern C++"一书中,他给出了一个例子:
class Annotation {
public:
explicit Annotation(const std::string text)
: value(std::move(text)) //here we want to call string(string&&),
//but because text is const,
//the return type of std::move(text) is const std::string&&
//so we actually called string(const string&)
//it is a bug which is very hard to find out
private:
std::string value;
};
Run Code Online (Sandbox Code Playgroud)
如果std::move禁止在const对象上操作,我们可以很容易地找出错误,对吧?
Moo*_*uck 99
这里有一个你可以忽略的技巧,即它std::move(cat) 实际上并没有移动任何东西.它只是告诉编译器尝试移动.但是,由于您的类没有接受a的构造函数const CAT&&,因此它将使用隐式const CAT&复制构造函数,并安全地复制.没有危险,没有陷阱.如果由于任何原因禁用了复制构造函数,则会出现编译器错误.
struct CAT
{
CAT(){}
CAT(const CAT&) {std::cout << "COPY";}
CAT(CAT&&) {std::cout << "MOVE";}
};
int main() {
const CAT cat;
CAT cat2 = std::move(cat);
}
Run Code Online (Sandbox Code Playgroud)
打印COPY,而不是MOVE.
http://coliru.stacked-crooked.com/a/0dff72133dbf9d1f
请注意,您提到的代码中的错误是性能问题,而不是稳定性问题,因此这样的错误不会导致崩溃.它只会使用较慢的副本.此外,对于没有移动构造函数的非const对象也会发生此类错误,因此仅添加const重载将无法捕获所有这些错误.我们可以检查是否能够从参数类型移动构造或移动赋值,但这会干扰应该返回到复制构造函数的通用模板代码.哎呀,也许有人希望能够建造const CAT&&,我是谁说他不能?
Yak*_*ont 47
struct strange {
mutable size_t count = 0;
strange( strange const&& o ):count(o.count) { o.count = 0; }
};
const strange s;
strange s2 = std::move(s);
Run Code Online (Sandbox Code Playgroud)
在这里我们看到了一个使用std::move上T const.它返回一个T const&&.我们有一个移动构造函数strange,它完全采用这种类型.
它被称为.
现在,这种奇怪的类型确实比您的提案修复的错误更为罕见.
但是,另一方面,现有std::move代码在通用代码中效果更好,您不知道您使用的类型是a T还是a T const.
How*_*ant 20
其余答案到目前为止忽略的一个原因是通用代码在移动时具有弹性的能力.例如,假设我想编写一个泛型函数,它将所有元素移出一种容器,以创建另一种具有相同值的容器:
template <class C1, class C2>
C1
move_each(C2&& c2)
{
return C1(std::make_move_iterator(c2.begin()),
std::make_move_iterator(c2.end()));
}
Run Code Online (Sandbox Code Playgroud)
很酷,现在我可以相对有效地创建一个vector<string>来自deque<string>每个人string将在此过程中移动.
但是,如果我想从一个移动map怎么办?
int
main()
{
std::map<int, std::string> m{{1, "one"}, {2, "two"}, {3, "three"}};
auto v = move_each<std::vector<std::pair<int, std::string>>>(m);
for (auto const& p : v)
std::cout << "{" << p.first << ", " << p.second << "} ";
std::cout << '\n';
}
Run Code Online (Sandbox Code Playgroud)
如果std::move坚持非const参数,则上述实例化move_each将无法编译,因为它正在尝试移动const int(key_type的map).但是这段代码并不关心它是否无法移动key_type.它出于性能原因想要移动mapped_type(std::string).
就这个例子而言,无数其他例子在通用编码中std::move就是移动请求而不是移动需求.
| 归档时间: |
|
| 查看次数: |
24033 次 |
| 最近记录: |