В С++ ООП, кто отвечает за удаление объекта, переданного конструктору

Например,

У меня есть класс генератора учетных записей, которому нужен случайный метод для определения имени пользователя и пароля. Random имеет много способов реализации, поэтому это интерфейс со многими подклассами. Класс генератора учетных записей принимает случайный объект в конструкторе.

В Java нас не волнует удаление объекта. Но сейчас я делаю это на C++. Мой вопрос в том, если бы я сделал следующее в main()

Random random=new StdRandom();
AccGen accGen=new AccGen(random);

должен ли я удалить «случайный» в main () или я должен поместить его в деструктор AccGen?

Редактировать:

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

Причина, по которой я использую указатель, заключается в применении многих шаблонов, таких как Factory и Behavior. Переменная без указателя, по-видимому, не может быть интерфейсом с чисто виртуальным методом, который не может представлять переопределения.

С точки зрения дизайна я думаю, что создатель объекта всегда несет ответственность за его удаление. Вот почему это приводит меня в замешательство. Все, что нужно вызывающей стороне, это объект AccGen. Я передал случайный объект, чтобы решить реализацию Random внутри AccGen. Тогда Random объект не является участником уровня вызывающего, тогда почему вызывающий должен нести ответственность за его удаление. Но дело в том, что рандом в некоторых случаях полезен в следующих действиях на уровне звонящего. Приведенный пример действительно просто пример.

После изучения интеллектуального указателя уникальный указатель действительно является решением моей проблемы. Это делает указатель более конкретным с точки зрения указания цели создания такого указателя.

Подводя итог, если объект полезен после передачи в конструктор, то тип будет чистым указателем и без удаления в деструкторе. Если объект бесполезен на уровне вызывающего объекта, то тип должен быть уникальным указателем.


person LeePai Chan    schedule 13.11.2019    source источник
comment
Кто в Java отвечает за потенциальные ресурсы, не связанные с памятью?   -  person Deduplicator    schedule 13.11.2019
comment
Это полностью зависит от вас. Концепция называется владение — владелец ресурса несет ответственность за очистку, но вам решать, кто является владельцем. Однако в современном C++ вы не должны использовать new — используйте интеллектуальные указатели, такие как std::unique_ptr или std::shared_ptr. Таким образом, у вас будет четкое право собственности, и вам никогда не придется беспокоиться об удалении объектов.   -  person Yksisarvinen    schedule 13.11.2019
comment
Как AccGen узнает, что указатель был создан при вызове new? Вы могли бы дать ему адрес нераспределенного объекта, т. е. Random random; AccGen accGen(&random);. Таким образом, вы не можете просто приравнять C++ к Java или попытаться выяснить, что делать с C++, учитывая, как работает Java.   -  person PaulMcKenzie    schedule 13.11.2019
comment
Это проклятие ручного управления памятью. Ответственной стороной является лицо, указанное в проекте в качестве ответственной стороны. Общее эмпирическое правило состоит в том, чтобы не разрабатывать свой путь к таким проблемам< /а>.   -  person user4581301    schedule 13.11.2019
comment
У вас где-то есть using Random = StdRandom*; или что Random random=new StdRandom(); должен делать?   -  person Ted Lyngmo    schedule 14.11.2019
comment
На самом деле код, который я разместил, был на Java. Но я думаю, что на мой вопрос дан ответ, умный указатель. Спасибо всем.   -  person LeePai Chan    schedule 14.11.2019


Ответы (2)


Мой вопрос в том, если бы я сделал следующее в main()

Random random=new StdRandom();
AccGen accGen=new AccGen(random);

Дело в том, что вы не знаете. Random не является типом указателя (если только это не вводящий в заблуждение псевдоним для SomeOtherType*), но new возвращает вам указатель на объект, который он создает.

Если вам нужны динамические распределения, вы можете сделать это вручную с помощью необработанных указателей и взять на себя полную ответственность за delete создание вещей, которые вы создали с помощью new:

Random* random = new StdRandom();
AccGen* accGen = new AccGen(random);
// ... do something ...
delete accGen;
delete random;

Это помогает привыкнуть к понятию собственности. Если один объект отвечает за управление временем существования второго экземпляра, говорят, что он «владеет» этим экземпляром.

Далее ресурсы приобретаются в конструкторе и освобождаются в деструкторе (подробнее об RAII если вы хотите узнать больше). Следовательно, вы могли бы подумать о том, чтобы позволить accGen взять на себя ответственность за удаление random в его деструкторе (*).

Делать это вручную не рекомендуется и не нужно. Используйте умные указатели. Вы можете забыть о new и delete, если просто позволите умным указателям делать грязную работу. В C++ нет мусора, хотя постоянное использование std::shared_ptr, вероятно, ближе всего к использованию сборщика мусора.

В любом случае, если вам не нужно выделять память динамически, то и не надо. C++ имеет семантику значений. В C++ вы получаете больше, чем просто ссылки на объекты, вы получаете сами объекты.

int main {
    StdRandom random;
    AccGen accGen{random};
    // ... use accGen ...
}   // <- end of scope

Не нужно ничего удалять. Объекты в стеке вызывают свой деструктор при выходе за пределы области видимости.

(*) = Если функции передается необработанный указатель, ожидается, что она не станет владельцем объекта, на который указывает. Функция не может знать, размещена ли она в стеке или динамически.

person 463035818_is_not_a_number    schedule 13.11.2019
comment
Возможная опечатка: чтобы сохранить тот же (предполагаемый) синтаксис указателя, AccGen accGen{random}; должно быть AccGen accGen{&random}; - person user4581301; 14.11.2019
comment
@user4581301 user4581301 на самом деле это было намеренно, чтобы последний пример был без каких-либо указателей. Скорее всего, StdRandom нельзя скопировать, но я не хотел раздувать ответ дополнительным обсуждением. - person 463035818_is_not_a_number; 14.11.2019
comment
@LeePaiChan Умный указатель может быть ответом. К сожалению, на примере, приведенном в вопросе, нельзя быть уверенным. Ничто в примере не предполагает, что вам нужно что-то большее, чем Автоматическая переменная. Помните, что в отличие от Java, вам не нужно new объекты. По возможности пусть среда выполнения позаботится об управлении за вас. - person user4581301; 14.11.2019

В C++ мы используем умные указатели, поэтому нам не нужно удалять.

person Oblivion    schedule 13.11.2019