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

Правильное использование (и) const_cast <>

В качестве общего правила очень часто считается неправильной практикой использовать const_cast<>() в коде на С++, поскольку он показывает (большую часть времени) недостаток в дизайне.

Пока я полностью согласен с этим, я, однако, задаюсь вопросом, в каких случаях использовалось const_cast<>(), это нормально и единственное решение.

Не могли бы вы, ребята, дать мне несколько примеров, которые вы знаете/вы встретили?

Большое спасибо.

4b9b3361

Ответ 1

const_cast также используется для удаления модификаторов volatile, как это реализовано в этой (противоречивой) статье:

http://www.drdobbs.com/184403766

Ответ 2

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

Ответ 3

Как и другие, основная цель состоит в том, чтобы удалить const из объектов, чтобы перейти к неконстантным корректным функциям, которые, как вы знаете, не будут изменять аргумент.

Существует трюк (by Meyers?), чтобы избежать дублирования кода, и он выглядит следующим образом:

struct foo
{
    const return_type& get(void) const
    {
        // fancy pants code that you definitely
        // don't want to repeat

        return theValue; // and got it
    }

    return_type& get(void)
    {
        // well-defined: Add const to *this,
        // call the const version, then
        // const-cast to remove const (because
        // *this is non-const, this is ok)
        return const_cast<return_type&>(static_cast<const foo&>(*this).get());
    }
};

Ответ 4

Я согласен с вашим утверждением, что его нормальное использование связано с тем, что вам нужно скрыть "недостаток дизайна".

IME - один из типичных сценариев использования, когда вы пытаетесь связать С++ с существующим C-кодом. Многие существующие C-коды принимают строки C как char *, даже когда строка не изменяется, тогда как они обычно представляются как нечто, которое преобразуется в const char * в С++. То, что импеданс несоответствует между двумя языками, которые вы обычно решаете с помощью const_cast. Конечно, вам лучше быть уверенным, что код, с которым вы взаимодействуете, не содержит каких-либо симпатичных идей об изменении передаваемых данных.

Я бы сказал, что он код пахнет во вновь написанном коде, но для взаимодействия со старым кодом C и С++ это необходимое зло. Тем не менее, я был бы крайне осторожен в отношении кода, который требует const_cast для любых объектов, отличных от POD, поскольку это обычно проблема, которая должна решаться на уровне разработки, а не на уровне кода.

Ответ 5

Одно законное использование (на мой взгляд) с итераторами std::set. Они всегда const, чтобы предотвратить изменение ключа, используемого в наборе. Изменение ключа нарушит внутреннюю структуру набора и вызовет поведение undefined.

Однако, пока ключ не изменяет его, безопасно изменять другие данные в объекте.

Скажем, у вас есть std::set, как это:

std::set<MyObject> some_set;

И класс вроде этого:

class MyObject {
    public:
        MyObject(const std::string &key)
            : key_(key) {}

        bool operator<(const MyObject &other) const {
            return key_ < other.key_;
        }

    private:
        // ...
        // <some other data>
        // ...

        const std::string key_;
};

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

Обычно вы можете получить ссылку const из набора итератора:

const MyObject &object = *some_set_iterator;

Но поскольку ключ const, он безопасен для const_cast разыменованного итератора:

MyObject &object = const_cast<MyObject &>(*some_set_iterator);

Ответ 6

Одно очень законное использование этого - когда у вас есть как const, так и non const api (для объектов const и non const соответственно), как в

class Bar {
   const SomeType& foo() const; 
   SomeType& foo();
}

Тогда, поскольку мы не хотим дублировать код в обеих функциях, мы часто используем

class Bar {
   SomeType& foo() {
      //Actual implementation 
   }
   const SomeType& foo() const {
        return const_cast<Bar*>(this)->foo();
   }
};

Это, конечно, предполагает, что foo не делает что-то, что нарушает семантику const.

Ответ 7

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