У меня есть класс, который содержит ссылки, такие как:
class A {
A(B &b) : b(b) {} // constructor
B &b;
}
Иногда b должен быть доступен только для чтения, иногда он доступен для записи. Когда я делаю const A a(b);
объект, очевидно, что я хочу защитить данные внутри него как const
,
Но — случайно — легко сделать неконстантную копию объекта, которая сделает данные внутри него уязвимыми.
const A a(b); // b object protected here
A a_non_const(a);
a_non_const.b.non_const_function(...); // b not protected now
Я думаю, что я должен как-то предотвратить копии объекта, когда он const
как это:
const A a(b);
const A a2(a); // OK!
A a_non_const(a); // Compiler error
Это вообще возможно?
const
const
Спецификатор типа управляет доступом к функциям-членам типа, а также доступом к его членам. Так как ваш член B & b
это ссылка, const
здесь ничего особенного для вас нет: в любом случае после инициализации ссылка не может быть изменена. Как вы получаете доступ к цель этой ссылки даже не рассматривается:
const A a(b);
a.b.non_const_function(); // OOPS, no problem!
Вместо (ab) используя const
Спецификатор типа вы можете добавить «флаг» к вашему типу, чтобы различать случаи, когда вам нужно иметь возможность неконстантного доступа, и случаи, когда вы этого не делаете:
#include <type_traits>
struct B {
void danger() {
}
void all_fine() const {
}
};
template<bool Writeable>
struct A {
using BRef = typename std::conditional<Writeable, B &, B const &>::type;
BRef b;
A (BRef b) : b(b) {};
};
using ConstA = A<false>;
using NonConstA = A<true>;
int main() {
B b;
ConstA a(b);
//NonConstA nc_a(a);
ConstA another_a(a);
//another_a.b.danger();
another_a.b.all_fine();
NonConstA a2(b);
a2.b.danger();
}
С некоторыми std::enable_if
Затем вы можете выборочно включать / отключать функции-члены A
в зависимости от того, нуждаются ли они в «записи» b
или нет.
НО Я хотел бы выделить этот комментарий еще больше:
«Иногда b должен быть доступен только для чтения, иногда он доступен для записи». Все ваши проблемы проистекают из этой странной двойственности. Я предлагаю выбрать один набор семантики для вашего класса, а не два
Вы, вероятно, должны вместо этого рассмотреть разделение вашего класса так, чтобы у вас был CommonA
с функциональностью, используемой как WriteableA
и NonWriteableA
(имена ужасные, но я надеюсь, вы понимаете, о чем я).
Вы можете сделать это для кучи:
static const A *constCopy(const A &a); // and of course implement it somewhere
Тогда вы не будете случайно изменять объект с помощью полученного указателя (который должен быть сохранен в const A *
в противном случае компилятор будет жаловаться).
Однако он не будет работать со стековыми объектами, так как возвращает const A &
локальной переменной является довольно смертельным действием, а «конструктор const» еще не был изобретен (связанный: Почему C ++ не имеет константного конструктора?)