Я сейчас борюсь со следующим предложением и хочу знать юридические и, в меньшей степени, моральные аргументы против него или за него.
Что у нас было:
#include <vector>
class T;
class C
{
public:
C() { }
~C( ) { /*something non-trivial: say, calls delete for all elements in v*/ }
// a lot of member functions that modify C
// a lot of member functions that don't modify C
private:
C(C const &);
C& operator=(C const&);
private:
std::vector< T* > v;
};
void init(C& c) { } // cannot be moved inside C
// ...
int main()
{
// bad: two-phase initialization exposed to the clients
C c;
init(c);
// bad: here follows a lot of code that only wants read-only access to c
// but c cannot be declared const
}
Что было предложено:
#include <vector>
class T;
class C
{
public:
C() { }
~C( ) { /*calls delete for all elements in v*/ }
// MADE PUBLIC
C(C const &); // <-- NOT DEFINED
// a lot of member functions that modify C
// a lot of member functions that don't modify C
private:
C& operator=(C const&);
private:
vector< T* > v;
};
C init() // for whatever reason object CANNOT be allocated in free memory
{
C c;
// init c
return c;
}
// ...
int main()
{
C const & c = init();
}
Это компилирует и связывает (и работает) с использованием последнего g++ (который является единственным целевым компилятором) как 4.1.2, так и 4.4.5 - из-за (N) RVO конструктор копирования никогда не вызывается; деструктор вызывается только в конце main().
Утверждается, что этот метод совершенно прекрасен, потому что невозможно неправильно использовать конструктор-копию (если он когда-либо был сгенерирован, это было бы ошибкой компоновщика), а его общедоступность предотвращает жалобы компилятора на частный.
Мне кажется очень-очень неправильным использовать такой трюк, который, как мне кажется, противоречит духу C++ и больше похож на хак - в плохом смысле этого слова.
Мои ощущения не являются достаточной аргументацией, поэтому я сейчас ищу технические детали.
Пожалуйста, не размещайте здесь учебники C++:
- Я знаю о «Правиле трех» и прочитал 12.8/15 и 12.2 Holy Standard;
- Я не могу использовать ни
vector<shared_ptr<T> >
, ниptr_vector<T>
; - Не могу выделить
C
в свободной памяти и вернуть изinit
черезC*
.
Спасибо.
init
может принимать (пустой) boost::Optional‹C› в качестве параметра by-ref, а затем создавать объект в этом необязательном, возвращая константную ссылку на объект внутри boost::Optional. В этом случае ctor по умолчанию также будет закрытым, аinit
будет сделанfriend
типа C. -- Просто идея. - person Martin Ba   schedule 05.04.2011