Правильное использование const_cast <> - PullRequest
37 голосов
/ 20 апреля 2010

Как правило, очень часто считается плохой практикой использовать const_cast<>() в коде C ++, так как он обнаруживает (в большинстве случаев) недостатки в дизайне.

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

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

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

Ответы [ 8 ]

26 голосов
/ 20 апреля 2010

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

18 голосов
/ 20 апреля 2010

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

Есть хитрость (от Мейерса?), Чтобы избежать дублирования кода, и она выглядит так:

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());
    }
};
17 голосов
/ 01 июля 2010

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

http://www.drdobbs.com/184403766

10 голосов
/ 20 апреля 2010

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

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

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

4 голосов
/ 22 мая 2014

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

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

Допустим, у вас есть 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 MyObject &object = *some_set_iterator;

Но так как ключ const, безопасно const_cast разыменованный итератор:

MyObject &object = const_cast<MyObject &>(*some_set_iterator);
2 голосов
/ 20 апреля 2010

Одно из самых законных применений этого - когда у вас есть как const, так и non const api (для const и не 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.

0 голосов
/ 16 марта 2019

Пример использования const_cast приведен в учебнике по программированию на c ++ (5-е издание). Функция ниже возвращает ссылку на константную строку

// return a reference to the shorter of two strings
const string &shorterString(const string &s1, const string
&s2)
{
    return s1.size() <= s2.size() ? s1 : s2;
}

В книге упоминается случай, когда нам нужна неконстантная ссылка.

Мы можем вызвать функцию для пары неконстантных строковых аргументов, но в результате мы получим ссылку на константную строку. Мы могли бы хотеть иметь версию shorterString, которая при неконстантности аргументы, приведет к простой ссылке. Мы можем написать эту версию наша функция использует const_cast:

string &shorterString(string &s1, string &s2)
{
    auto &r = shorterString(const_cast<const string&>(s1),
                            const_cast<const string&>(s2));
    return const_cast<string&>(r);
}

Эта версия вызывает постоянную версию shorterString, передавая ее аргументы к ссылкам на конст. Эта функция возвращает ссылку на константная строка, которую мы знаем, связана с одним из наших оригинальных, неконстантные аргументы. Поэтому мы знаем, что безопасно привести эту строку вернуться к простой строке и в ответ.

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

0 голосов
/ 20 апреля 2010

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

...