如何将rvalue转换为指针的左值?

时间:2015-11-18 16:50:56

标签: c++ c++11

class Attr
{
public:
   Attr();
   Attr(const std::wstring& name)
   {
      ...
   }
};

class AttrDec : public Attr
{
public:
   AttrDec(Attr* attr)
      :Attr()
   {
      _attr = attr;
   }
   AttrDec(Attr*&& attr)
      :Attr()
   {
      _attr = std::move(attr);
   }

private:
   Attr* _attr;
};

class XAttr : public AttrDec
{
public:
   XAttr(const std::wstring& name)
      :AttrDec(&Attr(name)) //HERE!!!
   {}
}

在标记位置我收到了警告:

  

使用的非标准扩展名:用作左值的类rvalue。

但是我在类AttrDec中定义了移动构造函数!

如何解决此警告?

4 个答案:

答案 0 :(得分:2)

解决这个问题的正确方法是按值存储,然后让移动做它的事情。移动指针不会移动仍然消失的基础临时值,并且你将有一个移动的悬空指针无处可寻:

class Attr
{
public:
   Attr();
   /*explicit depending on needs*/ Attr(const std::wstring& name)
   {
      ...
   }
}

class AttrDec : public Attr
{
public:
   AttrDec(Attr attr)
      :Attr()
      , attr_(attr)
   {
   }
   AttrDec(Attr&& attr)
      :Attr()
      , attr_(std::move(attr))
   {
   }

private:
   Attr attr_;
}

class XAttr : public AttrDec
{
public:
   XAttr(const std::wstring& name)
      : AttrDec(Attr(name)) //HERE!!!
   {}
}

答案 1 :(得分:0)

AttrDec(&Attr(name))正在尝试获取临时对象的地址。 address-of运算符只能在lvalues上使用。

您可以做的是将XAttr更改为

class XAttr : public AttrDec
{
public:
   XAttr(const std::wstring& name)
      :AttrDec(new Attr(name)) // create a pointer here
   {}
};

然后摆脱rvalue中的AttrDec构造函数。然后,您需要向AttrDec添加析构函数并删除其中的指针并添加复制构造函数以正确复制指针,否则会出现内存泄漏。有关资源管理类的更多信息,请参阅:What is The Rule of Three?

答案 2 :(得分:0)

Rvalues被添加到语言中以防止对象的大量复制,临时创建等,但指针本质上是简单的整数,所以你没有通过在int上使用它们获得任何东西。 使用rvalues的开销几乎肯定会高于复制指针。

答案 3 :(得分:0)

您需要终身管理。

Aasuming装饰上的非视图语义(装饰器拥有装饰),不需要值语义(如果您的基类是抽象的,很少见),这可能有效:

struct Attr {
  Attr();
  Attr(const std::wstring& name)
  {}
};

struct AttrDec : Attr {
  AttrDec(std::unique_ptr<Attr>&& attr){
    _attr = std::move(attr);
  }
private:
  std::unique_ptr<Attr> _attr;
};

struct XAttr : AttrDec {
  XAttr(const std::wstring& name)
   :AttrDec(std::make_unique<Attr>(name))
  {}
};

如果你的std缺少make_unique(C ++ 14),这是一个实现:

namespace notstd{
  template<class T,class...Args>
  std::unique_ptr<T> make_unique(Args&&...args){
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
  }
}

new的原始呼叫更清晰。

主要区别在于上述makrs所有权明确。

使用共享指针的变体,带有克隆支持的值语义指针,甚至视图指针都可以工作:最后一个选项需要XAttr在attr的第二个基类中提供独立存储。