Я пытаюсь передать 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;
}
В 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
,
Если вы не хотите выполнять какую-либо дополнительную работу в конструкторе, и предоставление всех возможных конструкторов базы не является проблемой, используйте наследующие конструкторы.
class B : public A {
using A::A;
};
Что происходит, так это то, что вы назвали переменные очень плохо.
Параметр конструктора называется так же, как переменная-член. Из-за этого в теле конструктора создается только переменная конструктора, а переменная-член назначается в списке инициализации независимо от того, что вы передаете (nullptr в вашем случае).
Чтобы решить проблему, переименуйте параметр конструктора:
A(std::unique_ptr<C> c1) : c(std::move(c1)){
if(c == nullptr){
c = std::unique_ptr<C>(new C);
c->x = 1;
}
}