Делать только постоянные копии постоянных объектов

У меня есть класс, который содержит ссылки, такие как:

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

Это вообще возможно?

2

Решение

недостаток в вашем коде: ваши данные не «защищены» даже с 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 (имена ужасные, но я надеюсь, вы понимаете, о чем я).

2

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

Вы можете сделать это для кучи:

static const A *constCopy(const A &a); // and of course implement it somewhere

Тогда вы не будете случайно изменять объект с помощью полученного указателя (который должен быть сохранен в const A *в противном случае компилятор будет жаловаться).

Однако он не будет работать со стековыми объектами, так как возвращает const A & локальной переменной является довольно смертельным действием, а «конструктор const» еще не был изобретен (связанный: Почему C ++ не имеет константного конструктора?)

2

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector