Шаблонные деструкторы C ++ для простых и сложных типов данных - PullRequest
2 голосов
/ 04 октября 2008

В связанном вопросе Я спросил о создании универсального контейнера. Использование полиморфных шаблонов кажется правильным решением.

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

Я хотел бы иметь возможность сделать что-то вроде

MyContainer<float> blah();
...
delete blah;

и

MyContainer<ComplexObjectType*> complexBlah();
...
delete complexBlah;`

Могу ли я сделать что-то подобное? Можно ли сделать это без умных указателей?

Опять же, спасибо за ваш вклад.

Ответы [ 5 ]

4 голосов
/ 04 октября 2008

Я бы порекомендовал, если вы хотите хранить указатели на сложные типы, что вы используете свой контейнер как: MyContainer<shared_ptr<SomeComplexType> >, а для примитивных типов просто используйте MyContainer<float>.

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


Вам не нужно много деструкторов, если вы используете свой контейнер таким образом. Как вы держите свои вещи в контейнере? Вы используете контейнер STL или массив в куче? Контейнер STL позаботится об удалении самого себя. Если вы удалите массив, это приведет к выполнению деструктора для каждого элемента, и если каждый элемент является shared_ptr, деструктор shared_ptr удалит указатель, который он сам удерживает.

1 голос
/ 04 октября 2008

Вы, скорее всего, do хотите использовать умные указатели здесь, это действительно упрощает проблему. Однако, как пример, довольно просто определить, является ли данный тип указателем. Грубая реализация (может быть более элегантной, но я не хочу вводить int2type):

typedef char YesType;
typedef char NoType[2];

template<typename T>
struct IsPointer
{
typedef NoType  Result;
};
template<typename T>
struct IsPointer<T*>
{
typedef YesType Result;
};

template<typename T>
struct MyContainer
{
~MyContainer()
{
    IsPointer<T>::Result r;
    Clear(&r);
    delete[] data;
}
void Clear(YesType*)
{
    for (int i = 0; i < numElements; ++i)
        delete data[i];
}
void Clear(NoType*) {}

T*  data;
int numElements;

};

0 голосов
/ 10 октября 2008

delete используется для освобождения памяти, ранее выделенной с new. Вам не нужно использовать здесь удаление, когда blah и complexBlah выходят из области видимости, они автоматически уничтожаются.

Хотя ответ yrp показывает вам один из способов использования специализации шаблонов для удаления содержащихся объектов, если они являются указателями, а не если нет, это выглядит как хрупкое решение. Если вам нужно такое поведение, лучше использовать библиотеки Boost Pointer Container , которые обеспечивают именно такое поведение. Причина, по которой стандартная библиотека этого не делает, заключается в том, что сами контейнеры не знают, контролируют ли они содержащийся указатель или нет - вам нужно обернуть указатель в тип, который знает - то есть, умный указатель.

0 голосов
/ 04 октября 2008

Если вы не хотите использовать умные указатели, попробуйте частичную специализацию шаблонов, это позволит вам написать шаблон, который используется только при установке контейнера с типом указателя.

0 голосов
/ 04 октября 2008

Это можно сделать, но это довольно продвинутый материал. Вам нужно будет использовать что-то вроде библиотеки MPL boost (http://www.boost.org/doc/libs/1_36_0/libs/mpl/doc/index.html)), чтобы вы могли получить деструктор MyContainer для выбора правильного вида разрушения, который он должен будет выполнять для отдельных элементов контейнера. И вы можете использовать увеличить библиотеку TypeTraits, чтобы решить, какой тип удаления требуется (http://www.boost.org/doc/libs/1_36_0/libs/type_traits/doc/html/index.html).. Я уверен, что она будет иметь черту, которая позволит вам решить, является ли ваш содержащийся тип указателем или нет, и, таким образом, решить, как это должно быть У вас может возникнуть необходимость реализовать признаки самостоятельно для любых других типов, которые вы хотите использовать в MyContainer, для которых есть какие-либо особые требования к удалению. Удачи вам! Если вы решите это, покажите нам, как вы это сделали.

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