2013-09-25 5 views
6

Я часто задавался вопросом,Что несет ответственность за удаление моего указателя?

Я знаю, что могу создать указатель на экземпляр объекта в то же время, проходя тот же указатель в качестве аргумента функции, используя ключевое слово new. Как и у меня ниже в функции Animation::newFrame, приведенной в примере ниже.

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

Так что, когда я называю конструктор кадра следующим образом:

Frame* myFrame 
    = new Frame(new point(0,0), new point(100,100), new point(50,20)); 

Где ответственность в конечном итоге освободить память для 3-х точек, я создал с помощью new в приведенном выше вызове функции лежат?

В конце концов, вышеупомянутые 3 новых пункта точно не имеют имен для меня, чтобы позвонить delete.

Я всегда считал, что они принадлежат к сфере функции, в которую они вызваны, и они просто выйдут из сферы действия с помощью функции. Однако в последнее время я думал, что это не так.

Надеюсь, я здесь был достаточно ясен.

Спасибо заранее,

Guy

struct Frame 
    { 
    public: 
     point f_loc; 
     point f_dim; 
     point f_anchor; 

    //the main constructor:: Creates a frame with some specified values 
     Frame(point* loc, point* dim, point* anchor) 
     { 
      f_loc = loc; 
      f_dim = dim; 
      f_anchor = anchor; 
     } 

    }; 

struct Animation 
    { 
    public: 
     vector<Frame*> frameList; 

    //currFrame will always be >0 so we subtract 1 
     void Animation::newFrame(int &currFrame) 
     { 
      vector<Frame*>::iterator it;//create a new iterator 
      it = frameList.begin()+((int)currFrame);//that new iterator is 

        //add in a default frame after the current frame 
      frameList.insert(
         it, 
         new Frame(
          new point(0,0), 
          new point(100,100), 
          new point(50,20))); 

      currFrame++;//we are now working on the new Frame 

     } 

     //The default constructor for animation. 
     //Will create a new instance with a single empty frame 
     Animation(int &currFrame) 
     { 
       frameList.push_back(new Frame(
        new point(0,0), 
        new point(0,0), 
        new point(0,0))); 

       currFrame = 1; 
     } 
    }; 

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

также приведенный выше пример взят из проекта шахты, что на самом деле C++/CLI и C++ смешанного (управляемые и неуправляемые классы), так что почему застройщик принимает только point* и не проходя по значению (point). Потому что point является неуправляемой структурой, поэтому, когда он используется в управляемом коде, должен управляться мной, программистом. :)

+1

этот код невозможно скомпилировать. несоответствие типов: f_loc = loc; также -1. вы должны были попытаться построить его самостоятельно. – thang

+4

Именно поэтому такие вещи должны передаваться по значению (а не создаваться «новым» на первом месте). Если вы создадите их с помощью 'new ', вы должны в любой момент вызвать' delete'on. – Hulk

+2

Почему вы настаиваете на выделении объектов в кучу (с помощью 'new')? Почему бы не использовать временные объекты, например: «Frame myFrame (точка (0,0), точка (100 100), точка (50,20));'. Это дешевле, потому что это позволяет избежать дорогостоящих распределений кучи и проблем с распределением памяти, которые вы наблюдали. – Andrzej

ответ

11

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

В вашем конкретном случае выше, Frame объект должен сам нести ответственность за delete ТРАЕКТОРИЯМИ 3 указателей, передаваемых в, и все, что построило Frame должен сам нести ответственность за delete ИНГАМИ что.

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

В C++, основной идиомы, используемый для достижения этих целей RAII и основные инструменты, используемые в auto_ptr (C++ 03), unique_ptr, shared_ptr и иже с ними. Boost также предоставляет ряд так называемых «умных указателей». Многие из этих параллельных найденных в C++ 11 (фактически, новые интеллектуальные указатели на C++ 11 были начальными, разработанными Boost), но есть и некоторые, которые выходят за рамки, например intrusive_ptr.

+0

Я должен был упомянуть, что я знаком и знаком с умными указателями и методом RAII. Вы имеете в виду, что в какой-то момент в конструкторе 'Frame', который я должен вызвать' delete loc; ',' delete anchor' и 'delete dim'? (Если бы я использовал необработанные, а не интеллектуальные указатели.) –

+0

@GuyJoelMcLean Если вы «новываете» их на пути, а затем «удаляете» их внутри, то почему вы используете 'new' вообще? Просто передайте 'point' по значению ... – Simple

+4

@GuyJoelMcLean Джон сказал это достаточно ясно: ** не используйте' new' или 'delete' **. – Walter

-1

извините, не полностью прочитал. Ответственность за удаление объектов, которые вы только что создали, несет ваша ответственность, если у вас нет ссылок на точки, которые вы должны создать деструктор внутри вашего объекта фрейма. http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fcplr380.htm

class X { 
    public: 
     // Constructor for class X 
     X(); 
     // Destructor for class X 
     ~X(); 
    }; 

X :: ~ X() автоматически вызывается на X объекта удаления.

Пожалуйста, исправьте меня, если я ошибаюсь.

1

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

2

Во-первых, ваш код необходимо скорректировать, чтобы он скомпилировался - вы, вероятно, не можете назначить point* на point (в зависимости от реализации point).

После того, как вы сделали это, ответ на ваш вопрос в том, что Animation необходимо освободить все на своем frameList и Frame необходимо освободить переданные в point* с. Необработанные указатели не будут удалены для вас.

Лучший ответ (хотя и не совсем то, что вы просили) заключается в том, что для управления памятью вы должны использовать shared_ptr или unique_ptr - они удалят выделенный объект для вас. Это определенно то, что я сделал бы для frameList - сделайте это std::vector<std::shared_ptr<Frame>>.

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

+1

+1 для передачи точки по значению или константной ссылки. Это намного проще и, вероятно, будет намного лучше, поскольку для этого не потребуется куча небольших распределений кучи. –

+0

Спасибо, я знаю, что этот пример не будет компилироваться в одиночку. Моя фактическая структура 'point' фактически содержит несколько операторов = перегрузки, которые позволяют присваивать' point * '' point'. –

+2

@GuyJoelMcLean Это ужасно! –

1

Если функция, которую вы вызываете, не указала явно, что она будет владеть переданными указателями delete, когда они будут выполнены, это ваша ответственность перед вами delete что угодно вы new.

+0

Как и в моем примере выше, могу ли я вызвать 'delete' в аргументах функций, если они указатели? –

1

Как я могу видеть из вашего фрагмента кода, текущая политика памяти - «передача права собственности». Например. вы создаете 3 экземпляра точки, а затем передаете их в конструктор кадров - с этого момента экземпляр Frame отвечает за управление этой 3-х точечной памятью. Таким образом, это означает, что вам необходимо предоставить деструктор для класса Frame, который будет отвечать за удаление памяти для каждого из трех точек, сохраненных в качестве члена.

Все, что указано выше, о «необработанной памяти» tecnique, которая не нужна новым дням. Вместо этого используйте интеллектуальные указатели. Например, std :: auto_ptr - хороший кандидат здесь (но помните о некоторых ловушках: если вы копируете один auto_ptr в другой, источник будет очищен до NULL, у адресата будет память). Другим широко распространенным кандидатом здесь является boost :: shared_ptr (он даже включен в последние стандарты C++ как часть пространства имен tr1 ::). И не забывайте: вы должны понимать политику памяти, предназначенную для выбранного вами умного указателя.В противном случае вы закончите разговор с призраками уничтоженных экземпляров, или ваши экземпляры никогда не будут освобождены, как джинн в бутылке.

1

Это зависит от соглашений. Это выглядит как часть графического интерфейса , а обычных соглашений в графическом интерфейсе заключается в том, что объект, содержащий , несет ответственность за delete после того, как он передал указатель . Таким образом, Animation будет delete все указатели в frameList в своем деструкторе и Frame удалят любые указатели, которые он удерживал в своем деструкторе. (Обратите внимание, что это соглашение очень требователен к ГПИ, однако, и что в большинстве других контекстов, другие конвенции будут использоваться.)

Сказав, что это также очень нетипичным в C++ для значения как Point для динамического назначения для начала, и также не было бы указателей на них.

Смежные вопросы