当虚拟基地移动分配操作符现在被允许使用时,它们会带来危险
Danger with virtual base move assignment operators when they are now allowed to be used?
这涉及C++问题的解决http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1402。摘要:
template<typename T> struct wrap { wrap() = default; wrap(wrap&&) = default; wrap(const wrap&) = default; T t; }; struct S { S(){} S(const S&){} S(S&&){} }; typedef wrap<const S> W; // Error, defaulted move constructor of "wrap<const S>" is deleted! W get() { return W(); }
(问题是,尽管编译器可以简单地使用"S"的复制构造函数,就像用户显式写入"wrap"的移动构造函数时一样,但我们在这个代码段中遇到了一个错误。解决了这个问题,在重载解决过程中忽略了已删除的移动构造函数(和赋值运算符),因此根据需要使用了上面的复制构造函数。)
在起草该决议时,对该决议发表了以下评论:
相对于复制,隐式/默认移动操作没有其他限制。这意味着在虚拟库中进行移动分配是危险的(编译器可能应该发出警告)[…]但我们在巴达维亚决定,我们不会针对隐式移动操作保留所有C++03代码,我认为此解决方案提供了显著的性能优势。
有人能描述一下虚拟基地移动分配操作员的担忧吗?
考虑:
#include <iostream>
struct A
{
A() = default;
A(const A&) = default;
A(A&&) = default;
A& operator=(const A&) {std::cout << "operator=(const A&)n"; return *this;}
A& operator=(A&&) {std::cout << "operator=(A&&)n"; return *this;}
};
struct B
: virtual public A
{
};
struct C
: virtual public A
{
};
struct D
: public B,
public C
{
};
int
main()
{
D d1, d2;
d1 = std::move(d2);
}
我认为这个程序应该输出:
operator=(A&&)
operator=(A&&)
对我来说,它实际上输出:
operator=(const A&)
operator=(const A&)
但我认为这只是一个clang bug(用-std=c++1y编译)。如果我对输出应该是什么是正确的,那么危险在于移动分配操作符被调用两次。这对于复制分配操作符是无害的(尽管可能很昂贵),但对于移动分配操作符则不是。
相关文章:
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- C++:TypeDef使用元组
- 使用std::multimap迭代器创建std::list
- 从不同线程使用int64的不同字节安全吗
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 既然存在危险,为什么项目要使用-I include开关
- 在C++的头文件中使用常量并在程序中询问其地址的任何潜在危险
- cppcheck 抱怨危险地使用 c_str(). c_str() 返回的值在此调用后无效
- cpp 检查抱怨危险使用 c_str(). c_str() 返回的值在本次调用后无效,如何解决?
- 使用危险的幻数N
- EiffelStudio 编译错误:使用 'tempnam' 很危险,最好使用 'mkstemp'
- 一次使用#pragma有什么危险
- 在构造器的初始化列表中使用"this"对Qt是否特别危险?
- 在不先显式调用析构函数的情况下,在旧对象上使用placement new是否危险
- 在不使用锁的情况下,危险指针如何安全地回收并发数据结构中的内存
- 使用对0指针的解引用是危险的
- std::reference_wrapper的隐式T&constructor是否会<T>使其使用起来很危险?
- 在c++中使用嵌套注释来快速(取消)激活代码块是有危险的
- 使用值包装器和 operator() 重载来简化 getter/setter 设计:这是一种危险的做法
- 从安全角度来看,在 Windows 中使用管道是否被认为是危险的