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

Std::vector объектов и const-correctness

Рассмотрим следующее:

class A {
public:
    const int c; // must not be modified!

    A(int _c)
    :   c(_c)
    {
        // Nothing here
    }

    A(const A& copy)
    : c(copy.c)
    {
        // Nothing here
    }    
};



int main(int argc, char *argv[])
{
    A foo(1337);

    vector<A> vec;
    vec.push_back(foo); // <-- compile error!

    return 0;
}

Очевидно, что конструктора копирования недостаточно. Что мне не хватает?

EDIT: Ofc. Я не могу изменить this- > c в методе operator =(), поэтому я не вижу, как будет использоваться оператор =() (хотя требуется std::vector).

4b9b3361

Ответ 1

Я не уверен, почему никто этого не сказал, но правильный ответ - отказаться от const или сохранить A* в векторе (используя соответствующий умный указатель).

Вы можете придать вашему классу страшную семантику, "скопировав" вызов UB или ничего не делая (и, следовательно, не являясь копией), но почему все эти проблемы танцуют вокруг UB и плохого кода? Что вы получаете, сделав это const? (Подсказка: ничего.) Ваша проблема концептуальна: Если класс имеет член const, класс const. Объекты, которые const, в принципе, не могут быть назначены.

Просто сделайте это неконстантным частным, и выставляйте его значение неизменно. Для пользователей это эквивалентно, const-wise. Это позволяет неявно сгенерированным функциям работать нормально.

Ответ 2

Элемент контейнера STL должен быть конструкцией с копией и назначаемым 1 (который не является вашим классом A). Вам нужно перегрузить operator =.

<суб > 1 : §23.1 говорит The type of objects stored in these components must meet the requirements of CopyConstructible types (20.1.3), and the additional requirements of Assignabletypes


ИЗМЕНИТЬ:

Отказ от ответственности. Я не уверен, что следующий фрагмент кода на 100% безопасен. Если он вызывает UB или что-то, сообщите мне.

A& operator=(const A& assign)
{
    *const_cast<int*> (&c)= assign.c;
    return *this;
}

РЕДАКТИРОВАТЬ 2

Я думаю, что приведенный выше фрагмент кода вызывает Undefined Behavior, потому что попытка отбросить константу переменной const вызывает UB.

Ответ 3

Вам не хватает оператора присваивания (или оператор присваивания копии), один из большой три.

Ответ 4

Сохраненный тип должен соответствовать требованиям CopyConstructible и Assignable, что означает, что необходим оператор =.

Ответ 5

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

Ответ 6

Я думаю, что реализация STL векторных функций, которые вы используете, требует оператора присваивания (см. цитату Prasoon из стандарта). Однако в соответствии с приведенной ниже цитатой, поскольку оператор присваивания в вашем коде неявно определен (поскольку он не определен явно), ваша программа плохо сформирована из-за того, что ваш класс также имеет член нестационарных данных const.

С++ 03

$12.8/12 - "Неявно объявленная оператор присваивания копий неявно определяется, когда объект его класса type присваивается значение его класса тип или значение типа класса полученный из его типа класса. Программа является неформальным, если класс, для которого a оператор присваивания копий неявно определено:

- нестатический член данных типа const или

- нестатические данные член ссылочного типа, или

- a нестатический член данных типа класса (или его массив) с недоступный оператор присваивания копии, или

- базовый класс с недоступным оператор присваивания копии.

Ответ 7

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

class A {
public:
    const int c; // must not be modified!

    A(int _c)
    ...

    A(const A& copy)
    ...  

    A& operator=(const A& rhs)
    {
        int * p_writable_c = const_cast<int *>(&c);
        *p_writable_c = rhs.c;
        return *this;
    }

};

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

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

Ответ 8

Обходной путь без const_cast.

A& operator=(const A& right) 
{ 
    if (this == &right) return *this; 
    this->~A();
    new (this) A(right);
    return *this; 
} 

Ответ 9

Недавно я столкнулся с той же ситуацией, и вместо этого использовал std:: set, потому что его механизм добавления элемента (insert) не требует оператора = (использует оператор < operator), в отличие от векторного механизма (push_back).

Если производительность является проблемой, вы можете попробовать unordered_set или что-то еще подобное.