2013-04-10 5 views
1

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

struct myStruc 
{ 
    int* m_p; 
} 

1. Вопрос: Где я должен удалить указатель? В деструкторе?

myStruct::~myStruct() 
{ 
    delete m_p; 
} 

2. Вопрос: Что делать, если указатель назначен на массив указателей, например,

myStruct mS; 
mS.m_p = new int[3]; 

Есть хороший способ (без dynamic_cast или попытаться прилов), чтобы теперь, если я должен сделать delete или delete[]?

+0

A/Путь заключается в том, чтобы выделить память в конструкторе и освободить его в деструкторе. –

+0

Можете ли вы рассказать больше о прецеденте? Какова цель myStruc? Кто устанавливает m_p? На что указывает m_p? Кто это решает и знает? –

+1

[Пункт 20: Избегайте использования данных в общедоступном интерфейсе.] (Http://www.amazon.com/Effective-Specific-Improve-Programs-Designs/dp/0321334876) –

ответ

3

Вы не должны ПОЗВОЛЯТЬ «пользователю», чтобы помешать указателям внутри ваших структур данных. Сделайте указатель закрытым и используйте функции get/set для доступа к нему.

Итак:

struct myStruc 
{ 
    private: 
    int* m_p; 
    public: 
    int* ptr() { return m_p; } 
    void allocate(int n) { m_p = new int[n]; 
    myStruc() : m_p(0) {}; 
    ~myStruc() { delete [] m_p; } 
}; 

Edit: Приведенный выше класс не является полным, он показывает концепцию. Для полного класса вам понадобится конструктор копирования и оператор присваивания и, вероятно, «запомните» n из функции allocate.

Теперь вам никогда не придется беспокоиться о том, что вы выделили [] или нет, поскольку это непротиворечиво.

Конечно, вы могли бы достичь этого, используя вместо этого std::vector, без каких-либо дополнительных усилий.

+0

У вашего кода возникли проблемы. Это не соответствует правилу трех. Это катастрофа в ожидании. –

+0

@AlokSave: Что именно вы имеете в виду? Недопустимый конструктор копирования? – ezdazuzena

+1

@ezdazuzena: Да. В этом случае всякий раз, когда объект копируется, будет использоваться неявно сгенерированный конструктор копирования, и он не сделает глубокую копию вашего члена данных. Это в основном означает, что вы получаете два объекта, относящихся к той же динамически распределенной памяти, как только один из них выходит из области действия, он освобождает память и дает вам обвисший указатель и UB. Можно утверждать, что класс не копируется или не присваивается, но для этого и конструктор копирования, и оператор присваивания должны быть объявлены как «частные» и не должны предоставляться никаким определением. –

0
  1. Идеально подходит для деструктора. Но следуйте за Rule of Three.
  2. Вы должны использовать delete[]. new/new[] следует использовать delete/delte[] соответственно.
+0

Что касается 2 .: Как мне теперь использовать новый int [3]? Что делать, если выполнено 'mS.m_p = new int();'? 'delete []' не сработает. – ezdazuzena

+0

Почему именно в деструкторе? Как структура может знать, следует ли удалять указатель или нет, или вызывать 'delete' или' delete [] '? – juanchopanza

+0

@juanchopanza С моей точки зрения, необработанный указатель обычно возвращает свои ресурсы в деструкторе. Я ответил на удаление части вашего комментария в 2. – Mahesh

2

В идеале вы не должны использовать сырой указатель. У вас есть два варианта: более

  1. Используйте std::vector или
  2. Используйте смарт-указатель в качестве члена и choose the right one as per your usage semantic.

Если вы не можете использовать смарт-указатель и должен использовать сырой указатель затем:

  • Если выделить указатель с помощью new затем использовать delete, если вы используете new [], то вам нужно использовать delete []. Не должно быть несоответствий.
  • Вы должны позвонить delete или delete [] каждый раз, когда срок службы этого динамически выделенного члена заканчивается. Предполагая, что время жизни этого члена совпадает с временем жизни вашего класса, оно будет находиться в деструкторе.
  • Важной частью является то, что вы должны следовать The Rule of Three.
+0

Я не использую boost. – ezdazuzena

+1

@ezdazuzena: Вам не нужен импульс. 'std :: vector' является частью языка с C++ 03, а если вы используете C++ 11, у вас есть множество умных указателей, из которых вы можете выбрать один. –

+0

Я согласен с этим ответом. Утверждение о том, что указатель не должен быть «public», пропускает этот пункт здесь, если предположить, что класс был правильно определен как «struct». – Gorpik

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