У меня есть следующий шаблонный класс, член которого имеет тип const ref. Копирование объекта отключено, и нужно было иметь только центр перемещения и оператор присваивания перемещения.
Q1: Как правильно реализовать оператор присваивания перемещения для const ref type (это правильно, что я сделал)?
2 квартал: Почему это
MyClass<int> obj2(std::move(obj)); // will work with move ctor
MyClass<int> obj3 = std::move(obj2); // also move ctor called: Why?
случилось?
3 квартал: В main() перемещенные экземпляры могут быть вызваны с помощью print(). Это UB?
Я использую Visual Studio 2015 (версия 140). Вот мой код:
#include <utility>
#include <iostream>
template<typename Type>
class MyClass
{
const Type& m_ref; // const ref type
public:
explicit MyClass(const Type& arg): m_ref(std::move(arg)){}
// coping is not allowed
MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;
// enables move semantics
MyClass(MyClass &&other) : m_ref(std::move(other.m_ref)) { std::cout << "Move Cotr...\n"; } // works
// how would I do the move assignment operator, properly: following?
MyClass& operator=(MyClass &&other)
{
// this should have been done in initilizer list(due to const ref member),
// but here we cannnot and still it gives no errors, why?
this->m_ref = std::move(other.m_ref);
std::cout << "Move =operator...\n";
return *this;
}
// print the member
const void print()const noexcept { std::cout << m_ref << std::endl; }
};
//test program
int main() {
MyClass<int> obj(2);
MyClass<int> obj2(std::move(obj)); // will work with move ctor
MyClass<int> obj3 = std::move(obj2); // also move ctor called: Why?
obj.print(); // why this prints 2? : is it UB?
obj2.print(); // why this prints 2? : is it UB?
obj3.print(); // here it makes sence.
std::cin.get();
}





Первый:
MyClass<int> obj2(std::move(obj)); // will work with move ctor
Второй:
MyClass<int> obj3 = std::move(obj2); // also move ctor called: Why?
Оба создают объекты (obj2 и obj3 соответственно) и инициализируют их. = не означает уступку в этом контексте.
У вас не может быть любой назначения члена const &. Вы можете вызывать операторы присваивания ссылочный объект.
Оба эти определения. Ни то, ни другое не является заданием. C++ имеет избыточный синтаксис.
Это не неопределенное поведение. Удаленный объект по-прежнему остается объектом. «Перемещение» int идентично копированию int, потому что нет смысла менять источник. MyClass<std::string> будет печатать пустую строку при перемещении из
Следует отметить, что operator= не имеет инициализатора члена, потому что объект уже существует.
Кажется, вы пытаетесь сделать std::reference_wrapper, предназначенный только для движения. Я не думаю, что это хорошая идея, так как ваши «ходы» на самом деле просто копии. C++ не позволяет создавать тип unique_reference. Самое близкое, что я могу придумать, - это std::unique_ptr<std::reference_wrapper<T>>, но даже в этом случае вы не можете гарантировать, что нет других ссылок на базовый объект.
Чтобы было ясно, вы не можете легко переместить объект, который содержит ссылочный член, к некоторому содержимому, которым он владеет.
Если нет владеет содержимым, вы, конечно, можете просто сделать копию этой ссылки; но если объект-донор в движении попытается удалить ссылку при уничтожении, у вас возникнет проблема, которую мы обсудим далее.
Вполне возможно, что целевое содержимое ссылки может быть перемещено, и тогда перемещение вашего объекта должно будет выполнить перемещение по ссылке, создав новый экземпляр этого элемента, на который имеется ссылка, который является «живым» и «убивает» оригинал. .
Другой вариант - использовать указатель вместо ссылки. Затем вы можете легко переместить указатель неглубоко, установив указатель-донор на nullptr. Вы можете создать оболочку для указателя, которая предоставляет ссылку на методы-заглушки, если их не слишком много, чтобы ваш существующий код оставался работоспособным. Любое прямое использование членов-значений не может быть так легко запутано.
Очень слабый вариант - иметь в объекте флаг, обозначающий право собственности. При движении флаг сбрасывается, а при уничтожении ссылки не уничтожаются, если флаг снят. Слабость в том, что если донор не удаляется сразу после перемещения, он находится в несогласованном состоянии. Члены, которые имеют были перемещены неглубоко, вероятно, больше не совместимы с ссылочным контентом, который все еще доступен.
Это было полезно