C++ C++;搬进集装箱

C++ C++;搬进集装箱,c++,vector,stl,move-semantics,c++17,C++,Vector,Stl,Move Semantics,C++17,假设我有一个容器,为了论证,让我们假设一个向量: std::vector<T> v; 但是,我没有移动赋值运算符 是否可以将键入T的值移动到向量中某个索引处的位置?类似于我可以在两个元素之间插入元素,或在末尾使用以下方法移动元素: v.emplace(std::move(value)); v.emplace_back(std::move(value)); 。。。每个人似乎都建议替换向量元素的一种方法是使用: v.at(index) = value; 但是,必须调用copy-ct

假设我有一个容器,为了论证,让我们假设一个向量:

std::vector<T> v;
但是,我没有移动赋值运算符

是否可以将键入T的值移动到向量中某个索引处的位置?类似于我可以在两个元素之间插入元素,或在末尾使用以下方法移动元素:

v.emplace(std::move(value));
v.emplace_back(std::move(value));
。。。每个人似乎都建议替换向量元素的一种方法是使用:

v.at(index) = value;
但是,必须调用copy-ctor的内容(或者按照规范调用opearator=copy的方式)。 我想到在元素上使用
std::swap
作为所需的索引和我希望移动的值,但是,这似乎有点浪费,因为我不再需要替换的值,如果我的类上没有定义
swap()
,那么std::swap似乎只是调用这两个元素的复制向量。。。这使得整件东西的价格翻了一倍

通常,我们应该如何在向量和stl容器中的索引处移动元素(如果可以推广)?有没有理由一开始就不可行

请注意,我想问的是,对于只定义了标准move-ctor的类型,这是如何实现的。如果在这些类型上定义swap(),我可以看到这变得相当容易。然而,swap方法的存在似乎并不常见,所以我宁愿避免这种情况。。。更不用说,当该方法不可用时,我必须用sfinae解决这个问题(这将使代码不可读),或者遭受双重调用复制构造函数的惩罚。

v.at(index)=std::move(value)
取决于是否存在移动赋值操作符。
std::swap
解决方案需要一个nothrow move赋值运算符

另外,定义
T::swap
肯定没有什么不好的,它可能比回到
std::swap
更有效

T
编写移动分配操作符将是一个很好的解决方案。如果您不能做到这一点,则可以就地创建和销毁,例如:

T *ptr = &v.at(index);
ptr->~T();
new(ptr) T( std::move(value) );
它依赖于
T
的move构造函数是noexcept,否则如果它抛出,您将被填充

使用
交换
或移动分配的一个很好的理由是,它本质上是异常安全的。移动分配运算符也将有利于其他容器操作。

v.at(index)=std::move(value)
取决于是否存在移动分配运算符。
std::swap
解决方案需要一个nothrow move赋值运算符

另外,定义
T::swap
肯定没有什么不好的,它可能比回到
std::swap
更有效

T
编写移动分配操作符将是一个很好的解决方案。如果您不能做到这一点,则可以就地创建和销毁,例如:

T *ptr = &v.at(index);
ptr->~T();
new(ptr) T( std::move(value) );
它依赖于
T
的move构造函数是noexcept,否则如果它抛出,您将被填充


使用
交换
或移动分配的一个很好的理由是,它本质上是异常安全的。移动分配操作符也将有利于其他容器操作。

emplace
也可以工作,但它会将插入点后的元素向后移动一个插槽。简单地说
v[i]=std::move(value)
?@David Haim在下面提到,问题的假设是没有定义该操作符。应该在帖子中提到。。。将编辑
emplace
也起作用,但它将插入点后的元素向后移动一个插槽。简单地
v[i]=std::move(value)
怎么样?@David Haim在下面提到,问题的假设是,所述运算符未定义。应该在帖子中提到。。。威尔·伊迪达,这就是我一直在寻找的答案。。。。我还应该明确提到假定缺少移动赋值运算符。但是我有一个问题:假设move-ctor不例外,那么新的抛出怎么可能呢?除了一个oom错误。。。但这些通常不会在正常情况下发生,并且无论如何都是不可恢复的。如果您没有移动赋值运算符,那么涉及赋值的容器操作将使用复制赋值(如果不存在,则无法编译)啊。。。nvm:p。我还认为ptr=newt(std::move(value))可能是更正常的语法?这两者有什么区别吗?我甚至不知道您使用的语法是有效的cpp tbh…@George您的建议将分配存储并创建一个与容器无关的对象。语法
new(p)
意味着在存储器中创建一个对象,该对象已经存在于
p
p->~T()所指向的位置意味着在不释放其存储空间的情况下销毁对象。。。这回答了我的下一个问题,那就是“这不会破坏数据位置吗?”:啊,这就是我一直在寻找的答案。。。。我还应该明确提到假定缺少移动赋值运算符。但是我有一个问题:假设move-ctor不例外,那么新的抛出怎么可能呢?除了一个oom错误。。。但这些通常不会在正常情况下发生,并且无论如何都是不可恢复的。如果您没有移动赋值运算符,那么涉及赋值的容器操作将使用复制赋值(如果不存在,则无法编译)啊。。。nvm:p。我还认为ptr=newt(std::move(value))可能是更正常的语法?这两者有什么区别吗?我甚至不知道您使用的语法是有效的cpp tbh…@George您的建议将分配存储并创建一个与容器无关的对象。语法
new(p)
意味着在存储器中创建一个对象,该对象已经存在于
p
p->~T()所指向的位置表示在不释放的情况下销毁对象