我有一个基类,它基本上将一个类附加到任意窗口句柄(例如,HWND,HFONT),并使用策略类来附加/分离和销毁:
// class SmartHandle
template<typename THANDLE, class TWRAPPER, class TPOLICY>
class SmartHandle : boost::noncopyable
{
private:
TPOLICY* m_pPolicy; // Policy
bool m_bIsTemporary; // Is this a temporary window?
SmartHandle(); // no default ctor
SmartHandle(const SmartHandle<THANDLE, TWRAPPER, TPOLICY>&); // no cctor
protected:
THANDLE m_hHandle; // Handle to the underlying window
TPOLICY& policy() {return(*m_pPolicy);};
// ctor that attaches but is temporary
SmartHandle(const THANDLE& _handle, bool _temporary) : m_hHandle(_handle)
, m_bIsTemporary(_temporary)
{
m_pPolicy = new TPOLICY(reinterpret_cast<TWRAPPER&>(*this));
if(_handle)
m_pPolicy->attach(_handle);
}; // eo ctor
// …Run Code Online (Sandbox Code Playgroud) 我前段时间听说我不应该创建具有std::string类型字段的异常类.这就是Boost网站所说的.基本原理是,std::string如果内存分配失败,复制构造函数可以抛出异常,如果在捕获当前处理的异常之前抛出异常,程序将终止.
但是,它仍然存在于移动构造函数的世界中吗?抛出异常时,不会使用移动构造函数而不是复制构造函数吗?我是否理解正确使用C++ 11不会发生内存分配,不存在异常的可能性,std::string现在在异常类中绝对正常?
在玩具类的移动构造函数的实现过程中,我注意到了一种模式:
array2D(array2D&& that)
{
data_ = that.data_;
that.data_ = 0;
height_ = that.height_;
that.height_ = 0;
width_ = that.width_;
that.width_ = 0;
size_ = that.size_;
that.size_ = 0;
}
Run Code Online (Sandbox Code Playgroud)
模式显然是:
member = that.member;
that.member = 0;
Run Code Online (Sandbox Code Playgroud)
所以我写了一个预处理器宏来减少冗长和容易出错:
#define STEAL(member) member = that.member; that.member = 0;
Run Code Online (Sandbox Code Playgroud)
现在实现如下:
array2D(array2D&& that)
{
STEAL(data_);
STEAL(height_);
STEAL(width_);
STEAL(size_);
}
Run Code Online (Sandbox Code Playgroud)
这有什么缺点吗?有没有更清洁的解决方案,不需要预处理器?
说我有以下功能
void doWork(Widget && param) // param is an LVALUE of RRef type
{
Widget store = std::move(param);
}
Run Code Online (Sandbox Code Playgroud)
为什么我需要param回到rvalue std::move()?是不是很明显,paramrvalue 的类型是因为它在函数签名中被声明为右值引用?不应该仅仅根据这个原则自动调用移动构造函数吗?
为什么不默认发生这种情况?
c++ rvalue-reference move-constructor lvalue-to-rvalue stdmove
根据标准,复制构造函数std::optional<T>:
......除非
is_copy_constructible_v<T>是,否则应被定义为删除true.
但是移动构造函数std::optional<T>:
......除非
is_move_constructible_v<T>是,否则不得参与超载决议true.
据我了解删除的构造函数,不删除move-constructor的目的std::optional<T>是允许这样的代码:
std::optional<X> o1;
std::optional<X> o2(std::move(o1));
Run Code Online (Sandbox Code Playgroud)
......依靠一些转换序列工作 - o2将由一个A使用a构造的类型的对象构造std::optional<X>&&(如果我错了,请纠正我).
但是对于可能的构造函数std::optional,我很难找到一个可以匹配这个用例的...
为什么移动构造函数std::optional<T>根本不被删除,如果T不是可移动构造的?
例
struct MyObject {
MyObject(int value):value(value) { }
MyObject(MyObject const&o):value(o.value) { }
int value;
};
Run Code Online (Sandbox Code Playgroud)
假设复制构造函数除了有用之外还做了一些事情.然后
std::function<void()> f() {
MyObject o;
std::vector<int> v;
return [=]() { /* use v and o */ &o; &v; }
}
Run Code Online (Sandbox Code Playgroud)
v并o首先复制到初始lambda对象,这很好.但是每次需要移动lambda对象时,它们都会被复制.虽然v 可以移动,但事实并非如此.那是因为lambda没有隐式移动构造函数,因为o没有移动构造函数或普通复制构造函数.
有人可以解释一下这背后的理由吗?
假设我有一个管理内存的类,因此需要用户定义的特殊成员函数(想象vector或类似).
考虑move-assignment运算符的以下实现:
Class& operator=(Class&& rhs)
{
this->~Class(); // call destructor
new (this) Class(std::move(rhs)); // call move constructor in-place
}
Run Code Online (Sandbox Code Playgroud)
以这种方式实现移动赋值运算符是否有效?也就是说,以这种方式调用析构函数和构造函数是否与语言中的任何对象生存规则相冲突?
以这种方式实现移动赋值运算符是一个好主意吗?如果没有,为什么不,并且有更好的规范方式?
看下面的代码:
struct node
{
node();
//node(const node&); //#1
//node(node&&); //#2
virtual //#3
~node ();
node*
volatile //#4
next;
};
int main()
{
node m(node()); //#5
node n=node(); //#6
}
Run Code Online (Sandbox Code Playgroud)
使用gcc-4.6.1编译时会产生以下错误:
g++ -g --std=c++0x -c -o node.o node.cc
node.cc: In constructor node::node(node&&):
node.cc:3:8: error: expression node::next has side-effects
node.cc: In function int main():
node.cc:18:14: note: synthesized method node::node(node&&) first required here
Run Code Online (Sandbox Code Playgroud)
据我所知,编译器无法在第6行创建默认移动或复制构造函数,如果我取消注释第1行或第2行它编译正常,这很清楚.代码在没有c ++ 0x选项的情况下编译正常,因此错误与默认移动构造函数有关.
但是,节点类中的内容会阻止创建默认移动构造函数吗?如果我评论任何第3行或第4行(即使析构函数非虚拟或使数据成员非易失性)它再次编译,那么这两者的组合是否使它不能编译?
另一个难题,第5行不会导致编译错误,与第6行有什么不同?它是否特定于gcc?还是gcc-4.6.1?
尝试编译以下代码:
struct Foo
{
explicit Foo ( void ) { }
explicit Foo ( Foo&& rhs ) { }
};
Foo bar ( void )
{
return Foo();
}
Run Code Online (Sandbox Code Playgroud)
收到以下错误:
调用隐式删除的'Foo'复制构造函数
好吧,很明显,拷贝代码被隐式删除了.
问题1:为什么编译器需要copy-ctor Foo?我期望使用move-ctor bar从rvalue构造返回值Foo().
然后我将move-ctor重新声明为隐式,并且所有内容都成功编译.
问题2:当我将move-ctor重新声明为隐式时,为什么编译器不再需要copy-ctor?
问题3:什么是explicit关键词意味着副本的背景和移动构建函数,因为它肯定意味着什么从正规构建函数的背景不同.
//code from https://skillsmatter.com/skillscasts/2188-move-semanticsperfect-forwarding-and-rvalue-references
class Widget {
public:
Widget(Widget&& rhs)
: pds(rhs.pds) // take source’s value
{
rhs.pds = nullptr; // why??
}
private:
struct DataStructure;
DataStructure *pds;
};
Run Code Online (Sandbox Code Playgroud)
我不明白设置的原因rhd.pds来nullptr.
如果我们删除此行会发生什么: rhs.pds = nullptr;
c++ ×10
move-constructor ×10
c++11 ×7
c++14 ×1
constructor ×1
exception ×1
g++ ×1
optional ×1
stdmove ×1
templates ×1