繁体   English   中英

分配给 std::array 数组中的 std::array 元素失败

[英]Assigning to std::array element in std::vector of arrays fails

今天,我正在努力理解一些对我来说很新的特性,特别是std::arraystd::vector 单独来看,这些行为似乎符合预期,但我对下面所示的行为感到非常困惑:

此版本有效:

printf("Using pointer:\n");
std::vector<std::array<int, 1>*> vap;
vap.push_back(new std::array<int, 1>());
printf("size of vector is %ld\n", vap.size());

printf("before setting value:\n");
printf("value is %d\n", vap.front()->at(0));
std::array<int, 1>* pvals = vap.front();
pvals->at(0) = -1;
printf("after setting value:\n");
printf("value is %d\n", vap.front()->at(0));

此版本不更新数组:

printf("Without pointer:\n");
std::vector<std::array<int, 1>> va;
std::array<int, 1> arr = {99};
va.push_back(arr);

像这样插入数组也会失败: va.push_back(std::array<int, 1>());

printf("size of vector is %ld\n", va.size());

printf("before setting value:\n");
printf("value is %d\n", va.front().at(0));
std::array<int, 1> vals = va.front();
vals[0] = -1;
printf("after setting value:\n");
printf("value is %d\n", va.front().at(0));

我正在尝试做的事情可能很明显,但如果有帮助,我会用散文写出来:

松散地,我正在创建一个整数数组的向量。 在示例的前半部分,我创建了一个指向这些数组的指针向量,并且能够通过指针插入一个新数组,然后修改该数组中包含的元素。 在下半场,我尽量避免使用指针。 该代码似乎成功插入了数组,但随后不允许我更改其中的元素。

我有点惊讶于在编译或运行时出现零警告或错误,我猜我错过了一些基本的东西。 接下来我可以尝试什么?

您正在处理数组的副本,您需要对向量中的数组的引用

int main() {
    vector<array<int, 1>> v;
    array<int, 1> a = { 99 };
    v.push_back(a);
    cout << v[0][0];
    auto& ar = v[0];
    ar[0] = 42;
    cout << v[0][0];
}

 99 42

你的va.push_back(arr); std::array<int, 1> vals = va.front(); 语句正在复制其源操作数。 因此,对这些副本所做的任何更改都不会影响源数组。

push_back的情况下,这可能是您想要的,因此您可以(例如)使用相同的源变量( arr )——经过适当的修改——将多个(不同的)数组推送到你的向量中。

但是,在第二种情况下,该副本几乎肯定不是您想要的。 相反,您应该声明一个引用变量并将其分配给您要修改的向量的元素。

在您在代码中显示的简单情况下,用法如下:

//...
std::array<int, 1>& vals = va.front(); // The "&" declares a reference
vals[0] = -1; // This now modifies the (element of the) array referred to.

但是请注意,在引用变量被声明和初始化为引用特定源之后,您不能重新分配它; 因此,随后的vals = va.at(2); 不会像你想的那样做(事实上,它会用 RHS 数组的副本替换之前提到的元素)。 一个值得注意的“例外”是在基于范围的for循环中使用此类引用变量时,如下所示:

for (auto& vals : va) {
   vals[0] = 42; // This will refer to a different "va" element each loop
}

类似地,您可以在更传统for循环内(或者,事实上,在任何循环或块范围内)显式定义这样的引用; 这将有效地在每次迭代循环时创建一个新引用(实际上,这也是上述基于范围的循环中所做的)。 因此,这段代码会将每个数组的第一个元素设置为循环的i索引:

for (size_t i = 0; i < va.size(); ++i) {
    auto& vals = va.at(i);
    vals[0] = static_cast<int>(i);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM