Если вы должны хранить const
ссылку на какой-то экземпляр типа B
в классе A
, то, конечно, вы хотите, чтобы обеспечить, что срок службы A
экземпляра будет превышено время жизни B
например:
B b{};
A a1{b}; // allowed
A a2{B{}}; // should be denied
B const f() { return B{}; } // const result type may make sense for user-defined types
A a3{f()}; // should also be denied!
Чтобы сделать возможным, вы должны явно указать = delete;
все перегрузки конструктора, которые могут принимать значения r (как const &&
, так и &&
). Для этого вам нужно всего лишь = delete;
const &&
версия конструктора.
struct B {};
struct A
{
B const & b;
A(B const & bb) : b(bb) { ; } // accepts only `B const &` and `B &`
A(B const &&) = delete; // prohibits both `B &&` and `B const &&`
};
Этот подход позволяет запретить передачу конструкторам всех видов rvalues.
Это также работает со встроенными скалярами.Например, double const f() { return 0.01; }
, хотя это вызывает предупреждение вроде:
предупреждения: «Const» квалификатор типа на тип возвращаемого значения не имеет никакого эффекта [-Wignored-классификаторов]
он все еще может имеет эффект, если вам просто = delete;
только &&
версия конструктора:
struct A
{
double const & eps;
A(double const & e) : eps(e) {} // binds to `double const &`, `double &` AND ! `double const &&`
A(double &&) = delete; // prohibit to binding only to `double &&`, but not to `double const &&`
};
double const get_eps() { return 0.01; }
A a{0.01}; // hard error
A a{get_eps()}; // no hard error, but it is wrong!
для монтажников без преобразования (т.е. не унарный) есть проблема: вы, возможно, придется предоставить = delete;
-d версии для всех в комбинаторно возможные варианты конструкторов следующим образом:
struct A
{
A(B const &, C const &) {}
A(B const &&, C const &&) = delete;
// and also!
A(B const &, C const &&) = delete;
A(B const &&, C const &) = delete;
};
, чтобы запретить смешанные-случаи, как:
B b{};
A a{b, C{}};
временный не связывается с ссылкой-значение. Определение 'r2' в вашем первом примере не должно компилироваться. – musiphil
Если вы используете VC++, одним из решений является повышение уровня предупреждения, и он скажет вам, когда он не работает. –
Однако ссылка _const_ будет привязываться к временному, так что вопрос по-прежнему очень хороший. Я рассмотрел этот подход, но я по-прежнему считаю, что если класс собирается хранить ссылку (или указатель) на указанном объекте, лучше взять указатель в конструкторе, чтобы потенциальные проблемы, связанные с жизненным циклом, бит более очевидный (когда конструктор принимает указатель, обычно это заставляет меня дважды подумать о том, что объект собирается с ним делать). –