oop — Использование наследования C ++ для улучшения класса с семантикой владения

У меня есть некоторые (на мой взгляд) довольно специфические требования к владельцам: у меня есть класс, который в основном интерпретирует массив значений типа double (это конкатенация некоторых довольно больших матриц), и я хочу общаться с библиотекой C, которая затем интерпретирует в другой способ (очень длинный математический вектор). В некоторых случаях я хочу интерпретировать указатель, который передается в функцию обратного вызова библиотекой C, то есть без получения права собственности. В этом случае копирование будет очень непрактичным. В других случаях я хочу выделить буфер самостоятельно и передать его в библиотеку C. В этом случае мой код владеет буфером.

Я создал «строительный блок», который интерпретирует двойной массив как матрицы (с boost::numeric::ublas::shallow_array_adaptor, но это в основном не имеет значения), вот так:

class Foo {
public:
explicit Foo(double *buffer);
Foo(const Foo &) = delete;
Foo(Foo &&) = delete;
Foo &operator=(const Foo &) = delete;
/* Some accessors. */
protected:
Foo &operator=(Foo &&) = default;
private:
/* Some things that store pointers into the buffer. */
};

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

Первая часть моего вопроса: Есть ли смысл пускатьFoo расширено с владением буфером «быть подклассом Foo?

Каждая операция Foo возможно сFooкроме того, владеющийFoo можно свободно копировать и перемещать. Пахнет, как принцип подстановки Лискова. Будучи в состоянии справиться с владениемFoo а также Foo Точно так же синтаксически, не написав кучу методов вFoo этот делегат переменной-члену очень удобный.

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

Я реализовал владениеFoo как это:

class OwningFoo : private std::unique_ptr<double[]>, public Foo {
public:
explicit OwningFoo(std::size_t size)
: std::unique_ptr<double[]>(new double[size]),
Foo(std::unique_ptr<double[]>::get()), size_(size) {
}
/* Implementation of copy and move constructors and
* assignment operators redacted. */
OwningFoo(const OwningFoo &);
OwningFoo(OwningFoo &&);
OwningFoo &operator=(const OwningFoo &);
OwningFoo &operator=(OwningFoo &&);
private:
std::size_t size_;
};

Моя вторая часть моего вопроса: Это хороший случай для множественного и частного наследования? Я стреляю в себя где-нибудь в ногу?

Обратите внимание, что если Foo не является членом, чем std::unique_ptr не может быть ни членом, потому что его нужно инициализировать до Foo,

0

Решение

То, как я это делаю, это продвигает проблему собственности дальше. Foo имеет буфер и знает, как его очистить, когда он уничтожен. У std :: shared_ptr есть обратный вызов уничтожения, который можно использовать, например, для этой цели. Это показывает принятый шаблон умного указателя знать, как этот конкретный экземпляр должен быть удален.

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

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

В упомянутом повороте, как код C, которому принадлежит буфер, координирует с временем жизни вашего класса? Звучит плохо, и если ваш класс знает, что он не владеет буфером (в хорошо инкапсулированном виде), это не меняет проблему кода C, не зная, когда ваш экземпляр будет создан с ним.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]