C ++: проблемы STL с постоянными членами класса - PullRequest
13 голосов
/ 30 июля 2010

Это открытый вопрос. Эффективный C ++. Item 3. Используйте const всякий раз, когда это возможно. Действительно?

Я хотел бы сделать что-нибудь, что не изменится в течение времени жизни объекта const. Но у const есть свои проблемы. Если у класса есть какой-либо член const, сгенерированный компилятором оператор присваивания отключен. Без оператора присваивания класс не будет работать с STL. Если вы хотите указать свой собственный оператор присваивания, требуется const_cast . Это означает больше шума и больше места для ошибок. Как часто вы используете постоянных учеников?

РЕДАКТИРОВАТЬ: Как правило, я стремлюсь к правильности, потому что я много многопоточности. Мне редко нужно реализовывать контроль копирования для моих классов и никогда не удалять код (если это не является абсолютно необходимым). Я чувствую, что текущее положение дел с const противоречит моему стилю кодирования. Const заставляет меня реализовать оператор присваивания, хотя он мне и не нужен. Даже без const_cast присваивание проблематично. Вам нужно убедиться, что все константные члены сравниваются одинаково, а затем вручную скопировать все неконстантные члены.

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

class Multiply {
public:
    Multiply(double coef) : coef_(coef) {}
    double operator()(double x) const {
        return coef_*x;
    }
private:
    const double coef_;
};

Ответы [ 14 ]

0 голосов
/ 30 июля 2010

Я бы использовал константный член, только если сам класс не копируется. У меня есть много классов, которые я объявляю с помощью boost :: noncopyable

class Foo : public boost::noncopyable {
    const int x;
    const int y;
}

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

#include <new>
#include <iostream>
struct Foo {
    Foo(int x):x(x){}
    const int x;
    friend std::ostream & operator << (std::ostream & os, Foo const & f ){
         os << f.x;
         return os;
    }
};

int main(int, char * a[]){
    Foo foo(1);
    Foo bar(2);
    std::cout << foo << std::endl;
    std::cout << bar<< std::endl;
    new(&bar)Foo(foo);
    std::cout << foo << std::endl;
    std::cout << bar << std::endl;

}

выходы

1
2
1
1

foo скопирован в bar с использованием оператора размещения new.

0 голосов
/ 30 июля 2010

В принципе, вы никогда не хотите помещать переменную-член const в класс. (То же самое с использованием ссылок в качестве членов класса.)

Constness действительно предназначена для потока управления вашей программы - для предотвращения мутации объектов в неправильное время в вашем коде. Поэтому не объявляйте переменные-члены const в определении вашего класса, а делайте все или ничего, когда вы объявляете экземпляры класса.

0 голосов
/ 30 июля 2010

Это не так уж сложно.У вас не должно возникнуть проблем с созданием собственного оператора присваивания.Биты const не нужно назначать (так как они являются const).

Обновление
Существует некоторое недопонимание того, что означает const.Это означает, что это никогда не изменится.

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

class CTheta
{
public:
    CTheta(int nVal)
    : m_nVal(nVal), m_pi(3.142)
    {
    }
    double GetPi() const { return m_pi; }
    int GetVal()   const { return m_nVal; }
    CTheta &operator =(const CTheta &x)
    {
        if (this != &x)
        {
            m_nVal = x.GetVal();
        }
        return *this;
    }
private:
    int m_nVal;
    const double m_pi;
};

bool operator < (const CTheta &lhs, const CTheta &rhs)
{
    return lhs.GetVal() < rhs.GetVal();
}
int main()
{
    std::vector<CTheta> v;
    const size_t nMax(12);

    for (size_t i=0; i<nMax; i++)
    {
        v.push_back(CTheta(::rand()));
    }
    std::sort(v.begin(), v.end());
    std::vector<CTheta>::const_iterator itr;
    for (itr=v.begin(); itr!=v.end(); ++itr)
    {
        std::cout << itr->GetVal() << " " << itr->GetPi() << std::endl;
    }
    return 0;
}
0 голосов
/ 30 июля 2010

Я думаю, что ваше заявление

Если в классе есть какой-либо член, сгенерированный компилятором оператор присваивания отключен.

Может быть неправильно. У меня есть классы, которые имеют метод const

bool is_error(void) const;
....
virtual std::string info(void) const;
....

, которые также используются с STL. Поэтому, возможно, ваше наблюдение зависит от компилятора или применимо только к переменным-членам?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...