В C ++ есть какие-либо общие рекомендации по обработке выделения / удаления памяти? - PullRequest
4 голосов
/ 20 июля 2010

Вероятно, все, что я прошу, - это ссылка на веб-сайт, который мне еще предстоит найти. Но исходя из фона Java, каковы общие рекомендации по обработке распределения и удаления памяти в C ++? Я чувствую, что могу добавлять в приложение все виды утечек памяти. Я понимаю, что есть несколько вариантов умных указателей, и вы тоже можете упомянуть их обо мне, но я бы хотел остановиться на стандартных указателях C ++.

Ответы [ 9 ]

17 голосов
/ 20 июля 2010

Моя обычная политика такова

  • Используйте умные указатели, где использование вообще сложно.
  • Все необработанные указатели принадлежат определенному объекту, который отвечает за его удаление.
  • Конструктор всегда выделяет указатель или инициализирует его нулем, если он будет установлен позже.
  • Деструктор всегда удаляет любые содержащиеся в нем указатели
  • Эти правила гарантируют, что указатели будут удалены при удалении принадлежащих им объектов, что устраняет наиболее распространенные ситуации утечки памяти.
  • Никогда не передавайте внутренний указатель в другой объект, всегда передавайте объект-контейнер и заставляйте вызываемые функции-члены вызывать функции объекта-контейнера для воздействия на «указатель».
  • Отключить копирование объекта контейнера. В редких случаях реализуйте копию так, чтобы она копировала указанный объект. Но никогда не позволяйте копировать принадлежащий объект, не копируя также содержащийся объект.
  • Два предыдущих правила гарантируют, что у вас не будет копий указателя, указывающего на удаленную память.
  • Не пытайтесь реализовать подсчет ссылок. Если вам нужен указатель с подсчетом ссылок, используйте класс интеллектуального указателя и укажите его.

Я обнаружил, что эти правила обычно обеспечивают безопасное и эффективное использование необработанных указателей, и если вы хотите нарушить эти правила, используйте вместо этого умный указатель.

5 голосов
/ 20 июля 2010

Используйте указатели с крайней паранойей.Для каждой переменной-члена, которую вы объявляете в классе, документируйте, владеет ли он временем жизни памяти, на которую он указывает.Если это так, то он отвечает за распределение и освобождение памяти.И если ему принадлежит память, на которую он указывает, запишите это ЯСНО!Также помните, выделите в конструкторе и освободите в деструкторе.Это великое правило, которое вы игнорируете на свой страх и риск.Также обнуляйте свои указатели, кроме случаев, когда вы их используете.Обнуляйте их, когда они инициализированы, и после того, как вы их освободите.Повсюду размещайте множество утверждений, проверяя целостность ваших указателей, ДО того, как вы разыграете их.Поместите настоящих охранников, чтобы справляться с ситуациями, когда они плохие.

Последнее и самое важное:

ПОЖАРА любой бозо в вашей компании, кто нарушает эти правила !!!Они буквально привносят неисчислимые повреждения в ваш продукт и вызывают множество ошибок и головных болей в будущем.

Редактировать: ссылка Favorite c ++ website

5 голосов
/ 20 июля 2010

Обычно мы используем new для выделения памяти и delete для ее освобождения.(Главным образом потому, что new вызывает соответствующие конструкторы, а delete соответствующие деструкторы).

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

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

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

4 голосов
/ 20 июля 2010

Соедините каждые new (или new[]) с delete (или delete[]).

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

4 голосов
/ 20 июля 2010

Я также пришел с Java, и потребовалось некоторое время, чтобы понять, как выглядит хороший дизайн в C ++.Сначала трудно подумать, кто несет ответственность за удаление вещей.Ответ состоит в том, чтобы передать эти обязанности объектам, позволить объектам владеть / управлять другими объектами или ресурсами и позволить им беспокоиться об удалении / выпуске или копировании.C ++ облегчает это с помощью конструкторов, деструкторов и т. Д. Ключевое слово «RAII» (получение ресурсов - инициализация).

Часто мне удается организовать отношение «x owns y» как лес, в котором деревокорни все живут в стеке (автоматическая память).Используя стандартные контейнеры и избегая указателей в качестве элементов данных, я уменьшаю количество новых / удаляемых вызовов в своем коде до минимума (почти ни одного).Это самая простая вещь для работы.Иногда вы можете почувствовать необходимость использовать умные указатели совместного владения, но по моему опыту люди склонны злоупотреблять ими.Но они, конечно, полезны в некоторых случаях.

1 голос
/ 20 июля 2010

Я использую следующую политику:

  • Никогда не используйте необработанные указатели, которые владеют объектами.

    Foo *f=new Foo(); // Bad!
    

    Даже в классах:

    class Bar {
         Bar(Bar const &); // non copyable
         void operator=(Bar const &);
    public:
          Bar() {
              f1_=new Foo();
              f2_=new Foo(); // this throws then f1_ never destroyed!
          }
          ~Bar() { delete f1_; delete f2_ ;} 
          Foo *f1_,*f2_;
    };
    // Bad code
    

    Правильно:

    class Bar {
         Bar(Bar const &); // non copyable
         void operator=(Bar const &);
    public:
          Bar() {
              f1_.reset(new Foo())
              f2_.reset(new Foo());
          }
          std::auto_ptr<Foo> f1_,f2_;
    };
    // Good code
    
  • Для объекта без общего владения используйте auto_ptr

    std::auto_ptr<Foo> f(new Foo()); // Good
    
  • Для совместного владения или контейнеров используйте boost::shared_ptr или std::tr1::shared_ptr

    std::vector<boost::shared_ptr<Foo> > foos;
    
  • Когда мне нужно передать право собственности на объект другому объекту, используйте auto_ptr

    void assign_foo(std::auto_ptr<Foo> f)
    {
       /// I own foo
    }
    
    std::auto_ptr<Foo> transfer_foo(std::auto_ptr<Foo> f) { ... } 
    // Now foo is owned by caller
    

    Так что это понятнокто дает кому указатель.

  • Необработанные указатели допускаются только как ссылки, которые могут быть нулевыми, и они никогда не владеют объектами

    void bar1(Foo *f) { do something with f if f!=NULL}
    
1 голос
/ 20 июля 2010

Если вам действительно нужно работать с необработанными указателями, то я предлагаю по возможности обернуть их умными указателями.Если вы будете хранить их в контейнере STL, вам нужно будет использовать tr1::shared_ptr вместо auto_ptr.

. Пока вы учитесь, я бы предложил избегать указателей, когда вы можетечтобы избежать головной боли.Например, если вам нужен массив int s, вы можете использовать vector вместо того, чтобы выделять и освобождать память самостоятельно.Если вы хотите создать экземпляр класса, сделайте это в автоматической памяти, то есть

MyClass myObject;

вместо

MyClass *myObject = new MyClass();
// ...
delete myObject;
0 голосов
/ 22 июля 2010

Как уже говорили другие, вам нужно прочитать RAII.Я нашел это полезным, когда изучал C ++, он старый, но дает основные идеи.

0 голосов
/ 20 июля 2010

Задумывались ли вы об использовании сборщика мусора. Этот Сборщик мусора в настоящее время используется проектом Mono, хотя я понимаю, что его заменяют более агрессивной версией. Это может помочь, так как при разработке на C / C ++ будет иметь такой же опыт, как и при разработке на Java.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...