Можно ли вернуть константную ссылку приватному члену? - PullRequest
22 голосов
/ 31 марта 2009

Мне нужно реализовать доступ только для чтения к приватному членскому контейнеру. Если я возвращаю постоянную ссылку, можно ли ее const_cast получить полный доступ к члену? Какую технику использовать?

Спасибо.

Ответы [ 8 ]

29 голосов
/ 31 марта 2009

Безопасно ли возвращать постоянную ссылку на приватный член

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

Возможно ли использовать const_cast для того, чтобы на самом деле возиться с членом

Да, и вы ничего не можете сделать, чтобы предотвратить это. Невозможно в любое время помешать кому-либо сбросить const в C ++. Это ограничение / особенность C ++.

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

21 голосов
/ 31 марта 2009

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

Что касается const_cast, помните, что "частный" спецификатор доступа в C ++ присутствует в качестве помощи программисту - он не предназначен для меры безопасности. Если кто-то хочет получить доступ к закрытым членам объекта, он может получить их независимо от того, что вы пытаетесь сделать, чтобы предотвратить это.

10 голосов
/ 31 марта 2009
const int &ref = your_object.your_function();
*(int*)&ref = 1234;
7 голосов
/ 31 марта 2009

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

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

// a.h
class A
{
public:
   A( int a ) : data_( a ) {}
   int get() const { return data_; }
private:
   int data_;
};

// malicious.h
class A;
void change( A& a, int new_value );

// malicious.cpp
//     does not include a.h, but redefines an almost exact copy of it
class A {
public:
   A( int a ) : data_( a ) {}
   int get() const { return data_; }
   int data_; // private removed
};
void change( A& a, int new_value )
{
   a.data_ = new_value;
}

// main.cpp
#include "a.h"
#include "malicious.h"
int main()
{
   A a(0);
   change( a, 10 );
   std::cout << a.get() << std::endl; // 10
}

Хотя приведенный выше код неверен (одно правило определения нарушено, существует два определения для класса A), факт заключается в том, что в большинстве компиляторов определение A и вредоносного A совместимы в двоичном формате. Код будет компилироваться и связываться, и в результате внешний код будет иметь доступ к вашим личным атрибутам.

Теперь, когда вы знаете об этом, не делайте этого . Позже это будет боль обслуживания в ***. Это стоило Microsoft немалых денег за обеспечение обратной совместимости с программным обеспечением, в котором использовались закрытые части возвращаемых объектов API (новые версии API, использующие тот же общедоступный интерфейс, но изменившие внутренние компоненты, могут нарушить работу некоторого стороннего кода приложения). С некоторым широко доступным программным обеспечением поставщик (в данном случае Microsoft) будет испытывать трудности с обеспечением обратной совместимости, но с менее известными приложениями этого не произойдет, и внезапно ваше ранее запущенное приложение выйдет из строя во всех отношениях.

5 голосов
/ 31 марта 2009

Я думаю, что это был Херб Саттер, который когда-то сказал, что нужно "Защититься от Мерфи, а не от Макиавелли". То есть вы должны сделать все возможное для защиты от неправильного использования кода случайно, но вы ничего не можете поделать с людьми, намеренно злоупотребляющими вашим кодом.

Если кто-то действительно хочет взломать ваш код, он может, даже если это на #define private public, перед тем как включить заголовок (и, таким образом, создать нарушение ODR, но я отвлекся).

Так что да, возвращать const ref нормально.

5 голосов
/ 31 марта 2009

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

1 голос
/ 31 марта 2009

Есть возможность получить полный доступ. Но зачем?

Не забудьте сделать аксессор верным

const MyType& getMyValue() const;

Также вы можете ввести ваше личное значение в обратном вызове.

void doJob( callback c )
{
    c( myPrivateValue_ );
}
1 голос
/ 31 марта 2009

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

...