Деструктор класса C ++ удалить член, если "владелец"? - PullRequest
0 голосов
/ 30 августа 2018

Я знаю в C ++, что указатель - это просто указатель на область памяти, и здесь нет понятия «владельцы». Но рассмотрим следующую ситуацию (не обязательно хороший код):

class A {
public:
    A(){}
    ~A()
    { if(myObject!=nullptr)
        delete myObject;
    }

    void createMember()
    {myObject=new CrazyCustomClass();}

    CrazyCustomClass *getMember()
    {return myObject;}
private:
    CrazyCustomClass *myObject=nullptr;
}

Если это имеет значение, CrazyCustomClass НЕ имеет конструктора копирования, так как нет смысла его копировать. Так довольно просто - у меня есть класс, который в какой-то момент после создания экземпляра может вызвать new для создания экземпляра члена типа CrazyCustomClass *

Проблема в том, что если в какой-то момент у меня будет создана копия class A (что нормально - я хочу иметь возможность скопировать class A). Когда эта копия удалена, то же самое относится и к объекту, на который указывает экземпляр класса original . Например:

void StupidFunction(A *firstObject){
//This is NOT a real function, it simply illustrates the effect of a third-party library function
    //create a new object that is a copy of first object
    A secondObject(*firstObject);
    <do whatever with second object>
    //secondObject goes out of scope here and gets deleted.
}

A *firstObject=new A();
firstObject->createMember();
stupidFunction(firstObject);
CrazyCustomClass *customObject=firstObject.getMember(); //this is now an invalid pointer

В приведенном выше примере StupidFunction из сторонней библиотеки, идея в том, что она дает «временную» копию объекта, с которой вы можете работать, не связываясь с исходным объектом, что хорошо. Class A и CrazyCustomClass оба являются моими кодами и могут быть изменены по желанию. К сожалению, когда «временная» копия удаляется, то, как я написал свой деструктор, вызывает проблемы.

Моей первой мыслью было использовать shared_ptr, что-то вроде этого:

std::shared_ptr<CrazyCustomClass> sharedObject=std::make_shared<CrazyCustomClass>(new CrazyCustomClass);

... но это дало мне ошибку при компиляции:

Конструктор-кандидат (неявный конструктор копирования): недопустим: нет известное преобразование из CrazyCustomClass * в const CrazyCustomClass за 1-й аргумент; разыменовать аргумент с помощью *

и если я делаю разыменование аргумента с *, это дает мне ошибку об удаляемом конструкторе копирования "CrazyCustomClass", что верно - нет разумного способа скопировать CrazyCustomClass.

Итак, мой вопрос: как я могу рефакторировать class A таким образом, чтобы myObject правильно удалялся, когда firstObject выходит из области видимости, но не , когда удалялись любые "временные" копии A

1 Ответ

0 голосов
/ 31 августа 2018

Использование shared_ptr на самом деле является решением этой проблемы, однако код, указанный в исходном вопросе, неверен. Существует два (как минимум) различных способа инициализации shared_ptr (ref: https://msdn.microsoft.com/en-us/library/hh279669.aspx).). Во-первых, вы можете сделать это, используя new в качестве аргумента конструктора:

shared_ptr<CrazyCustomClass> myObject(new CrazyCustomClass)

Во-вторых, и это, как правило, предпочтительный метод, вы можете использовать функцию make_shared (как и в оригинальной публикации), которая принимает не объект new, а аргументы для передачи конструктор объекта, в данном случае ничего:

shared_ptr<CrazyCustomClass> myObject=make_shared<CrazyCustomClass>()

Исходный код просто перепутал эти два метода, что привело к ошибкам в конструкторе копирования: он пытался создать новый объект CrazyCustomClass с указателем на объект CrazyCustomClass в качестве аргумента конструктора.

После использования shared_ptr, delete в деструкторе должен быть удален.

Наконечник шляпы @tkausl и @alterigel за указание на ошибку в комментариях к вопросу!

...