Безусловно, самый простой способ сделать это — использовать std::shared_ptr<double[]>
вместо необработанного указателя double*
. Все будет Просто Работать™, и вам не придется думать о копирующих и перемещающих конструкторах или деструкторах (сравните правило нуля).
Могут быть веские причины не использовать shared_ptr
. Например, shared_ptr
должен использовать атомарный подсчет ссылок, чтобы быть потокобезопасным, даже если ваш код никогда не будет совместно использовать массив между потоками. Это может быть немного медленнее, в зависимости от платформы. А для shared_ptr
обычно требуется два выделения: одно для контрольного блока со счетчиком ссылок и средством удаления, другое для фактических данных. Хотя shared_ptr
это необходимо для поддержки эффективных слабых ссылок и из-за деталей стандарта C++, ваша реализация языка C++ может позволить вам использовать более компактное представление с использованием гибкого члена массива в стиле C. Тогда примерно:
struct Inner {
size_t refcount;
size_t capacity;
double data[]; // !!! not ISO C++ !!!
};
struct SharedDataArray {
Inner* inner;
SharedDataArray() : inner(nullptr) {}
explicit SharedDataArray(size_t capacity) : SharedDataArray() {
if (!capacity) return;
inner = reinterpret_cast<Inner*>(std::malloc(
sizeof(Inner) + capacity * sizeof(double)
));
if (!inner) throw std::bad_alloc();
inner->refcount = 1;
inner->capacity = capacity;
std::fill(inner->data, inner->data + capacity, 0);
}
SharedDataArray(SharedDataArray& other) : inner(other.inner) {
if (!inner) return;
++(inner->refcount);
}
~SharedDataArray() {
if (!inner) return;
--(inner->refcount);
if (inner->refcount > 0) return;
std::free(inner);
inner = nullptr; // not strictly necessary
}
};
Но это сложно сделать правильно, и вам действительно стоит подумать об использовании вместо этого shared_ptr
. Предпочтительно shared_ptr<vector<double>>
, поскольку он управляет жизненным циклом массива за вас за счет дополнительной косвенности указателя.
Прикрепляю к посту несколько видео по теме: