Проблема, которую я пытаюсь решить, возникает при создании контейнеров, таких как std::vector
объектов, которые содержат элементы данных reference и const:
struct Foo;
struct Bar {
Bar (Foo & foo, int num) : foo_reference(foo), number(num) {}
private:
Foo & foo_reference;
const int number;
// Mutable member data elided
};
struct Baz {
std::vector<Bar> bar_vector;
};
Это не будет работать как есть, потому что оператор присваивания по умолчанию для класса Foo
не может быть создан из-за ссылочного члена foo_reference
и константного члена number
.
Одним из решений является изменение этого foo_reference
на указатель и избавление от ключевого слова const
. Это, однако, теряет преимущества ссылок над указателями, и что const
член действительно должен быть const
. Они являются частными членами, поэтому единственное, что может причинить вред, - это мой собственный код, но я выстрелил себе в ногу (или выше) своим собственным кодом.
Я видел решения этой проблемы в Интернете в виде swap
методов, которые кажутся чопорными с неопределенным поведением, основанным на чудесах reinterpret_cast
и const_cast
. Случается, что эти методы работают на моем компьютере. Сегодня. С одной конкретной версией одного конкретного компилятора. Завтра или с другим компилятором? Кто знает. Я не собираюсь использовать решение, основанное на неопределенном поведении.
Похожие ответы по stackoverflow:
Так есть ли способ написать swap
метод / конструктор копирования для такого класса, который не вызывает неопределенное поведение, или я просто облажался?
Редактировать
Просто чтобы прояснить, я уже хорошо знаю это решение:
struct Bar {
Bar (Foo & foo, int num) : foo_ptr(&foo), number(num) {}
private:
Foo * foo_ptr;
int number;
// Mutable member data elided
};
Это явно устраняет const
ness number
и устраняет подразумеваемое const
ness foo_reference
. Это не решение, которое я ищу. Если это единственное не UB решение, пусть будет так. Мне также хорошо известно об этом решении:
void swap (Bar & first, Bar & second) {
char temp[sizeof(Bar)];
std::memcpy (temp, &first, sizeof(Bar));
std::memcpy (&first, &second, sizeof(Bar));
std::memcpy (&second, temp, sizeof(Bar));
}
, а затем написание оператора присваивания с использованием функции копирования и замены. Это обходит проблемы со ссылками и константой, но это UB? (По крайней мере он не использует reinterpret_cast
и const_cast
.) Некоторые из изменяемых изменяемых данных являются объектами, которые содержат std::vector
s, поэтому я не знаю, будет ли работать такая мелкая копия, как эта.