将本地 std::array 移动到传递的 std::array& 参数



我对将std::array操作移动到引用传递的std::array容器感到困惑。

我在哪里读到评论这被认为是未定义的行为,还是正确的结果?

还是它真的复制了元素?

#include <iostream>
#include <array>
#include <algorithm>
using namespace std;
void printElements(string description, array<uint8_t,16>& arr)
{
cout << description << ":t";
for(auto i:arr)
{
cout << (int)i << " ";
}
cout << "n";
}
void assignToArr(array<uint8_t,16>& in_out_arr)
{
array<uint8_t,16> arr2;
arr2.fill(4);
move(arr2.begin(),arr2.end(),in_out_arr.begin());
printElements("before arr2 destruction", in_out_arr);
printElements("arr2 before fill(5)", arr2);
arr2.fill(5);
printElements("arr2 after fill(5)", arr2);
}
int main()
{
array<uint8_t,16> arr1;
assignToArr(arr1);

printElements("after arr2 destruction", arr1);

return 0;
}

结果:

before arr2 destruction:        4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4                                                                                      
arr2:   4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4                                                                                                              
arr2:   5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5                                                                                                              
after arr2 destruction: 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4   

当您在C++中移动一个琐碎的类型时,它会被复制。

C++中的移动操作告诉类型;我们不依赖于源数据后来的样子,可以自由地做一些更高效的事情";。对于琐碎的类型(如int(,归零或以其他方式更改源没有任何好处。

事实并非如此。

对于更复杂的类型,如std::vector<int>,从中移动通常会导致空的std::vector<int>(并非总是!不能保证;只是旧向量可以有效地赋值或销毁(。

std数组将其数据存储在内部,因此如果类型本身是琐碎的(如果其中的数据是琐碎的,那么它本身就是琐碎的(,则没有有效的移动改进。

这里的琐碎是指C++标准中使用的一个术语。

std::array将元素直接存储在数组对象内部。这就是为什么它的大小必须是一个编译时常数。当您尝试移动std::array时,数组本身不会移动,因为这是不可能的,但里面的元素会移动。移动对象时会发生什么取决于类型。通常,复制廉价的复制类型(intdouble等(对从对象复制的对象没有影响。将更复杂的对象(std::string和其他容器(从中移出;未指明的";状态这意味着它不是未定义的行为,而是未指定的行为。这是一个例子:

#include <array>
#include <iostream>
class Stateful final {
private:
bool m_specifiedState = true;
int m_value = 0;
public:
bool hasSpecified() const noexcept { return m_specifiedState; }
int value() const noexcept { return m_value; }
Stateful(int val) noexcept : m_value(val) {}
Stateful(Stateful const& other) noexcept = default;
Stateful& operator=(Stateful const& other) noexcept = default;
Stateful(Stateful&& other) noexcept
: m_specifiedState(other.m_specifiedState), m_value(other.m_value) {
other.m_specifiedState = false;
}
Stateful& operator=(Stateful&& other) noexcept {
if (this != &other) {
m_specifiedState = other.m_specifiedState;
m_value = other.m_value;
other.m_specifiedState = false;
}
return *this;
}
};
std::ostream& operator<<(std::ostream& os, Stateful const& s) {
if (s.hasSpecified())
os << s.value();
else
os << '?';
return os;
}
template <auto N>
std::ostream& operator<<(std::ostream& os, std::array<Stateful, N> const& arr) {
os << "[ ";
for (auto const& elm : arr) os << elm << ' ';
os << "]";
return os;
}
int main() {
std::array<Stateful, 3> arr1{1, 2, 3};
std::cout << "Arr1             :" << arr1 << 'n';
std::array<Stateful, 3> arr2 = std::move(arr1);
std::cout << "Arr1 (moved from):" << arr1 << 'n';
std::cout << "Arr2 (moved to)  :" << arr2 << 'n';
}

请参阅联机

输出为:

Arr1             :[ 1 2 3 ]
Arr1 (moved from):[ ? ? ? ]
Arr2 (moved to)  :[ 1 2 3 ]

正如您所看到的,moved-from数组仍然存在,并且仍然有3个元素,但元素本身已经移动。

我已经回答了我自己的困惑,std::array不存储引用,而是直接在堆栈中存储对象。所以它们是不可移动的,但实际上是复制的。

最新更新