Подтвердить что ты не робот

Можно ли возвратить ссылку const для частного участника?

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

Спасибо.

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Можно ли использовать const_cast для фактического беспорядка с элементом

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

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

Ответ 3

const int &ref = your_object.your_function();
*(int*)&ref = 1234;

Ответ 4

Не беспокойтесь о том, что пользователи, выполняющие 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 и malitious A бинарно совместимо. Код будет компилироваться и связываться, а результат заключается в том, что внешний код имеет доступ к вашим приватным атрибутам.

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

Ответ 5

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

Ответ 6

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

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

Итак, да, вернемся назад, const ref отлично.

Ответ 7

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

Ответ 8

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

Не забудьте сделать конструктор доступа const const

const MyType& getMyValue() const;

Кроме того, вы можете ввести свое частное значение в обратном вызове.

void doJob( callback c )
{
    c( myPrivateValue_ );
}

Ответ 9

Согласно книге Скотта Мейера " Эффективно" C++ (см. Пункт № 28), вам следует избегать этого. Вот выдержка из пункта № 28:

Вот почему любая функция, которая возвращает дескриптор внутренней части объекта, опасна. Не имеет значения, является ли дескриптор указателем, ссылкой или итератором. Неважно, является ли его квалифицированным с const. Неважно, является ли функция-член, возвращающая дескриптор, самой константой. Все, что имеет значение, это то, что дескриптор возвращается, потому что, как только это будет сделано, вы рискуете, что дескриптор переживет объект, на который он ссылается.