Правильная инициализация unique_ptr в конструкторе базового класса

Я пытаюсь передать 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

0

Решение

В A::ctor вы используете переменную c но это не ссылка на члена класса A::c но ссылка на локальную переменную c который является параметром ctor. Поэтому после выхода из 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,

3

Другие решения

Если вы не хотите выполнять какую-либо дополнительную работу в конструкторе, и предоставление всех возможных конструкторов базы не является проблемой, используйте наследующие конструкторы.

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

Что происходит, так это то, что вы назвали переменные очень плохо.

Параметр конструктора называется так же, как переменная-член. Из-за этого в теле конструктора создается только переменная конструктора, а переменная-член назначается в списке инициализации независимо от того, что вы передаете (nullptr в вашем случае).

Чтобы решить проблему, переименуйте параметр конструктора:

  A(std::unique_ptr<C> c1) : c(std::move(c1)){
if(c == nullptr){
c = std::unique_ptr<C>(new C);
c->x = 1;
}
}
1
По вопросам рекламы [email protected]