У меня есть вопрос о хорошем стиле C ++:
Я хотел бы написать класс «MyClass», который имеет один или несколько указателей в качестве членов, и MyClass может выделять память для этих указателей. Я хотел бы использовать неявный дать по умолчанию-копировать-конструктор (а также оператор по умолчанию-назначения), чтобы скопировать экземпляр MyClass, так что были скопированы только указатели и новый объект совместно использовать данные, которые имеет исходный объект выделены.
Моя идея заключалась в том, чтобы запретить копируемые объекты (созданные с помощью конструктора копирования или оператора присваивания) освобождать память (а также выделять память для указателей на элементы). Чтобы различить скопированные объекты и исходные объекты (созданные конструктором), я хочу использовать следующий код:
class MyClass
{
public:
MyClass(): originalPtr(this) { data = new char[100000]; }
~MyClass() { if(originalPtr == this) delete[] data; }
private:
MyClass *originalPtr;
char *data; // shared data (not copiable)
char otherFeatures[10]; // individual data (copiable)
};
Будет ли это решение (используя сравнение с this
— указатель) хороший стиль для такой цели (например, разбор объекта по вызову по значению) или это рискованно? Конечно, я предполагаю, что исходный объект живет всегда дольше, чем скопированные объекты.
Спасибо!
Нет, это плохая идея. Если указатели используются несколькими экземплярами, то последний должен умереть последним, а не исходным. Это отличается в том смысле, что первоначальный может не быть тем, кто умрет, что заставит всех остальных указывать на мусор. Даже если вы предполагаете, что он умирает последним, вы должны понимать, что внутренняя работа класса не должна опираться на внешние предположения. То есть класс не имеет гарантий того, как его жизненный цикл управляется остальной частью реализации, поэтому он не должен делать предположений.
В этой ситуации вы должны отслеживать ссылки на ваши данные. Основная идея состоит в том, чтобы отслеживать, сколько у вас есть экземпляров класса. Как только это число достигает нуля, вы можете освободить эту память; последняя копия только что умерла. К счастью для тебя, STL уже обеспечивает такую реализацию. Они известны как Умные Указатели. Есть и другие, такие как станд :: unique_ptr, что делает обратное, гарантируя, что данные принадлежат только одному экземпляру.
Хорошо, предполагая общий случай, когда исходный объект не умирает наконец. Мне нравится идея просто считать экземпляры. Например, можно использовать такую концепцию:
class MyClass
{
public:
MyClass(): countOfInstances(new int())
{
++*countOfInstances;
data = new char[100000];
}
~MyClass()
{
--*countOfInstances;
if(!countOfInstances)
{
delete[] data;
delete countOfInstances;
}
}
MyClass(const MyClass &other) // analogous for the assignment operator
{
countOfInstances = other.countOfInstances;
data = other.data;
otherFeatures = other.otherFeatures;
++*countOfInstances;
}
private:
int *countOfInstances;
char *data; // shared data (not copiable)
char otherFeatures; // individual data (copiable)
};
Здесь также следует убедиться, что разделяемая память полностью распределена, прежде чем делать копии.