Проблема, которую я пытаюсь решить, возникает при создании контейнеров, таких как std :: vector
, объектов, содержащих ссылочные и константные элементы данных:
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_vector;
};
Это не будет работать как есть, потому что оператор присваивания по умолчанию для класса Foo
не может быть построен из-за ссылочного члена foo_reference
и константного члена number
.
Одно из решений состоит в том, чтобы заменить foo_reference
указателем и избавиться от ключевого слова const
. Однако при этом теряются преимущества ссылок перед указателями, и что ] const
член действительно должен быть const
. Это частные члены, поэтому единственное, что может навредить, - это мой собственный код, но я выстрелил себе в ногу (или выше) своим собственным кода.
Я видел решения этой проблемы в Интернете в виде методов подкачки
, которые, кажется, переполнены неопределенным поведением, основанным на чудеса reinterpret_cast
и const_cast
. Бывает, что эти методы действительно работают на моем компьютере. Сегодня. С одной конкретной версией одного конкретного компилятора. Завтра или с другим компилятором? Кто знает. Я не собираюсь использовать решение, основанное на неопределенном поведении.
Связанные ответы по stackoverflow:
Так есть ли способ написать метод подкачки
/ конструктор копирования для такого класса, который не вызывает неопределенное поведение, или я просто облажался?
Изменить
Просто чтобы это сделать ясно, я уже хорошо осведомлен об этом решении:
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 of ] 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, поэтому я не Не знаю, подойдет ли здесь такая мелкая копия.