Есть ли у частного нового оператора неожиданные побочные эффекты? - PullRequest
4 голосов
/ 14 мая 2011

Я прочитал в этом блоге, что создание нового частного оператора является хорошим подходом для принудительного создания экземпляров в стеке.

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

  • У меня вопрос: есть ли у этого побочные эффекты, которые не так просто увидеть?
  • Это хороший подход для обеспечения реализации в стеке?
  • Есть ли проблемы с переносимостью?

Спасибо за вашу помощь!

EDIT

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

Цель состоит в том, чтобы просто предоставить простую возможность настроить платформу и перевести ее в состояние готовности к использованию без необходимости создания 10 объектов в клиентском коде.

Ответы [ 3 ]

7 голосов
/ 14 мая 2011

Этот класс, очевидно, должен создаваться только в стеке, поэтому я ищу способ обеспечить его выполнение.

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

Основной недостаток заключается в том, что не работает .

Даже если новые операторы являются частными, пользователи все равно могут случайно использоватьваш класс как член данных или базовый класс их собственного класса, а затем создать экземпляр класса с помощью new.Это останавливает их написание Foo *f = new Foo();, когда они должны писать Foo f;, но это не заставляет их использовать ваш класс RAII в соответствии с лексической областью действия, что, вероятно, вы действительно хотели бы применить.

Если кто-то хочет использовать блокировку (или что-то еще) с динамическим сроком хранения, то он либо очень умен, либо действительно глуп.В любом случае, если вы позволите им создать его самостоятельно, вы не сможете помешать им обойти ваши ограничения.

Что вы можете сделать, это сделать все конструкторы приватными (включая ctor-копию), а затем предоставить функцию Friend.который возвращается по значению.Они должны написать:

const Foo &f = GimmeAFoo();

, который требует стандарт, продлит срок жизни возвращаемого значения до объема f.Так как они не могут скопировать объект, они не могут заставить значение покинуть область ссылки.Поскольку они не могут инициализировать элемент данных или базовый класс, они не могут использовать обходной путь.Обратите внимание, что они должны использовать константную ссылку, поэтому, на самом деле, она не работает, если вашему классу нужны неконстантные члены.

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

2 голосов
/ 14 мая 2011

Я реализую класс, который использует идиому RAII. Этот класс, очевидно, должен создаваться только в стеке, поэтому я ищу способ применить это.

Это не RAII. RAII инициализируется при построении и деинициализации в деструкторах. RAII касается ресурсов, которыми вы управляете (например, члены данных), а не времени жизни «родительского» объекта. Пользователи вашего типа затем снова применяют RAII для управления временем жизни того, что они выделяют. Например, вы можете динамически распределить std :: vector, даже если vector использует RAII, чтобы убедиться, что каждый элемент , который он «владеет», очищен.


Мой вопрос: есть ли у него какие-либо побочные эффекты, которые не так просто увидеть?

Да, вы предотвращаете использование вашего типа (по крайней мере, в отношении RAII).

void example() {
  shared_ptr<T> p (new T());
  // No RAII violation, still uses operator new.

  vector<T> v (some_initial_size);
  // No RAII violation, still uses operator new (the placement form is used
  // inside the default allocator).
}

Это хороший подход для принудительного создания экземпляров в стеке?

Что вы пытаетесь предотвратить? Какой вариант использования? Любой, кто использует new с вашим типом, либо 1) знает, что он делает, и нуждается в нем, либо 2) ужасно испортит управление ресурсами, независимо от того, что вы делаете. Вы препятствуете тем, кто находится в # 1, не помогая тем, кто находится в # 2, пытаясь применить это.

Это еще один способ заявить, что сказал Стив:

Этот класс, очевидно, должен создаваться только в стеке, поэтому я ищу способ применить это.

Если это очевидно, зачем его применять?

Если пользователи будут слепо использовать «new T ()», что заставляет вас думать, что они не будут слепо использовать «:: new T ()»?


Цель состоит в том, чтобы просто предоставить простую возможность настроить платформу и перевести ее в состояние готовности к использованию без необходимости создания 10 объектов в клиентском коде.

#include <framework>

int main() {
  framework::Init init;
  // Do stuff.
}

Используйте это или что-то очень близкое к этому, что заметно в примерах ваших документов.

2 голосов
/ 14 мая 2011

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

Поскольку это весь действительный код C ++, проблем с переносимостью нет.

...