Проблема, которую я пытаюсь решить, возникает при создании контейнеров, таких как 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> bar_vector;
};
Это не будет работать, потому что оператор присваивания по умолчанию для класса Foo
не может быть создан из-за ссылочного элемента foo_reference
и const member number
.
Одним из решений является изменение этого foo_reference
на указатель и избавление от ключевого слова const
. Это, однако, теряет преимущества ссылок на указатели и что член const
действительно должен быть const
. Они являются частными членами, поэтому единственное, что может нанести вред, это мой собственный код, но я застрелился в ноге (или выше) с помощью своего собственного кода.
Я видел решения этой проблемы в Интернете в виде методов swap
, которые кажутся переполненными поведением undefined, основанным на чудесах reinterpret_cast
и const_cast
. Бывает, что эти методы, похоже, работают на моем компьютере. Cегодня. С одной конкретной версией одного конкретного компилятора. Завтра или с другим компилятором? Кто знает. Я не буду использовать решение, основанное на undefined.
Похожие ответы по stackoverflow:
- Имеет ли смысл реализовать оператор копирования в классе со всеми членами данных const?
В первом ответе есть забавная строка "Если эта неизменная, ваша привинченная". - Метод обмена с членами константы
Первый ответ действительно не применим здесь, а второй - немного клочья.
Итак, есть способ написать конструктор метода /t < > t29 > для такого класса, который не вызывает поведение undefined, или я просто привинчен?
Edit
Чтобы это было ясно, я уже прекрасно понимаю это решение:
struct Bar {
Bar (Foo & foo, int num) : foo_ptr(&foo), number(num) {}
private:
Foo * foo_ptr;
int number;
// Mutable member data elided
};
Это явно исключает const
n 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));
}
а затем запись оператора присваивания с использованием copy-and-swap. Это касается проблем ссылки и const, но это UB? (По крайней мере, он не использует reinterpret_cast
и const_cast
.) Некоторые из разрешенных изменяемых данных являются объектами, которые содержат std::vector
s, поэтому я не знаю, будет ли здесь работать неглубокая копия.