正确地在基类的构造函数中初始化unique_ptr

时间:2014-05-26 09:33:09

标签: c++ c++11 move-semantics unique-ptr ctor-initializer

我尝试将std::unique_ptr传递给继承的类,该类将它转发给基类构造函数(使用构造函数初始化列表)。如果基类构造函数接收到nullptr,则应构造默认对象并将其分配给我的基类的std::unique_ptr成员变量。但不知怎的,我得到了一个AccessViolation,如果我试图从任何地方std::unique_ptr访问任何元素(因为它仍然是nullptr - 即使此时不可能这样做。)

这里有什么想法吗?

#include <iostream>
#include <memory>

class C{
public:
  int x;
};

class A{
public:
  A(std::unique_ptr<C> c) : c(std::move(c)){
    if(c == nullptr){
      c = std::unique_ptr<C>(new C);
      c->x = 1;
    }
  }
  void print(){
    std::cout << c->x << std::endl;
  }
private:
  std::unique_ptr<C> c;
};

class B : public A{
public:
  B(std::unique_ptr<C> c) : A(std::move(c)){
  }
};

int main(int argc, char* argv[]){
  B b(nullptr);
  b.print();
  return 0;
}

https://ideone.com/fHvYqe

3 个答案:

答案 0 :(得分:3)

A::ctor中,您使用的是变量c,但它不是引用类成员A::c,而是引用作为ctor参数的局部变量c。因此,在ctor退出后,A::c将为nullptr,因此您无法在A::print函数中取消引用它。

  A(std::unique_ptr<C> c) : c(std::move(c)){
    if(c == nullptr) {               // here c is ctor parameter (local variable)
      c = std::unique_ptr<C>(new C); // A:c is still nullptr
      c->x = 1;                      // 
    }
  }

可能的解决方案是为局部变量c名称和A::c创建不同的名称,例如A::m_c

答案 1 :(得分:2)

如果你不想在构造函数中做任何额外的工作,并且提供基础的所有可能的构造函数都不是问题,请使用继承构造函数。

class B : public A {
  using A::A;
};

答案 2 :(得分:1)

您发生的变数非常糟糕。

构造函数的参数与成员变量的名称相同。因此,只在构造函数体中创建构造函数的变量,并且在初始化列表中分配成员变量,无论您传递什么(在您的情况下为nullptr)。

要解决此问题,请重命名构造函数的参数:

  A(std::unique_ptr<C> c1) : c(std::move(c1)){
    if(c == nullptr){
      c = std::unique_ptr<C>(new C);
      c->x = 1;
    }
  }