这里已经提到了vector vs valarray的问题.我的问题专门针对C++ 11的情况.我一直在阅读"C++之旅"和"C++编程语言".这两本书都是由Bjarne Stroustrup撰写的.在第一本书中,作者解释说std::valarray应该首选数值计算(第12章).但是在第二章的第29章中,作者用a实现了一个Matrix类std::vector.
通过谷歌搜索,似乎在性能方面,a std::vector与动态分配"原始数组"一样快.
那么在C++ 11的上下文中,哪个容器应该是数值计算的首选?
我对此的看法是,因为std::vector使用operator[](它返回对数据的引用而没有边界检查)提供对其内容的快速访问,并且使用std::vector动态分配的数组也更安全,std::vector应该是首选.此外,从C++ 11开始:
std::vector 使用提供对底层数据的直接访问 std::vector::data()std::vector::shrink_to_fit()当我遇到一些我认为是编译器STL实现中的错误时,我正在玩valarrays.这是我可以生成的最小的例子:
#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
#include <valarray>
using namespace std;
int main()
{
valarray<int> Y(0xf00d, 1);
valarray<valarray<int>> X(Y, 1);
cout << "Y[0] = " << std::hex << Y[0] << '\n';
cout << "X[0][0] = " << std::hex << X[0][0] << '\n';
cout << "X[0].size() = " << X[0].size() << '\n';
cout << "X.sum().size() = " << X.sum().size() << '\n';
}
Run Code Online (Sandbox Code Playgroud)
这将输出:
$ g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
Y[0] = f00d …Run Code Online (Sandbox Code Playgroud) 标准库中是否有一个功能允许我切片std::slice或者我需要编写类似的东西
std::slice refine(std::slice const& first, std::slice const& second)
{
return {
first.start() + second.start() * first.stride(),
second.size(),
first.stride() * second.stride()
};
}
Run Code Online (Sandbox Code Playgroud)
我自己?
C++11std::begin(std::valarray&)以及std::end(std::valarray&).
C++17 引入了std::data()它与std::vector, std::array, C 风格的数组等一起使用。但是为什么没有为std::data()引入重载std::valarray?
std::valarray被指定为具有连续存储,可以通过获取a[0](见注释)的地址来访问。
std::data(std::valarray& a)可以简单地定义为 return &(a[0])。为什么没有做到这一点?是疏忽吗?
我的动机是我正在开发一个通用的序列化库。当它从源(例如 CBOR)接收连续的二进制数数组时,它会检测目标容器是否具有重载data(container)函数、container.resize(n)成员函数以及适当的value_type(匹配原始数字类型)。这三者的存在使得memcpy()将源数据直接高效地导入目标容器成为可能。如果有std::data(std::valarray&)超载,它会让我的生活更简单。缺少它并不是一个阻碍,但它确实使代码更加混乱。
附录:我想检测一个data函数的原因是它告诉我目标容器是连续的。如果它是连续的,那么我可以进行有效的字节复制(通过std::memcpy或std::copy无关紧要)。如果它不是连续的,那么我解压每次打开一个未对齐的源阵列头号和使用它附加到目标容器push_back,emplace等取决于容器的类型。
附录 2:我决定使用适配器和特征方法,而不是检测data函数的存在。这将使支持非标准或用户定义的容器类型变得更加容易。我关于为什么没有std::data(std::valarray& a)仍然站的问题。
附录 3:我应该澄清一下,我需要对 CBOR 类型的数组(只能是数字)执行此操作。此外,源缓冲区中的数字未与元素边界对齐。我知道二进制数据可能需要字节序交换,如果不小心处理,将字节复制到浮点类型可能会触发奇怪的 NaN 行为。
我现在后悔提到我的动机,应该让这个std::data(std::valarray& a)问题独立存在。这个问题已经变成了一个火车事故,哈哈。:-)
是的,之前已经问过,答案是:
valarrays(值数组)旨在将Fortran的一些速度带入C++.你不会做一个valarray指针,所以编译器可以对代码做出假设并更好地优化它.(Fortran速度如此之快的主要原因是没有指针类型,因此不存在指针别名.)
要么:
valarray也应该消除任何混叠的可能性[...]
但这些答案对我来说毫无意义.
valarray并且vector是类模板,因此,它们在实例化之前甚至不存在.
当然,a vector<int>不会导致混叠问题valarray<int>.
鉴于此,它的目的是什么valarray,为什么它们不是简单地将相同的功能放入其中vector呢?
我有一个vector<vector<double>表格(矩阵)值.列包含行星的位置和速度,因此行存储同一行星的数据.我想在a中变换一行,valarray因为我需要数学运算.然后我想将valarrays(行星)存储在矢量中.我试过这样的:
vector<vector<double>> corps_tmp=configFile.get_corps(); // The function returns a vector<vector<double>>
valarray<double> corpX;
for (int i(0); i < corps_tmp.size(); i++) {
corpX = corps_tmp[i]; // I want to save the first row of the vector<vector<double>> on the valarray
corps.push_back(corpX); // I want to ''add'' the valarray to a vector.
corpX = 0;
}
Run Code Online (Sandbox Code Playgroud)
这段代码不起作用,我在向valarray指定向量时显然是错误的(显然是不允许的).
有没有办法以一种简单的方式实现我的目标?
为什么std::valarray不支持自定义分配器?如何设计其内存管理?是否使用new基于或malloc基于分配器?所有其他容器通常提供指定自定义分配器的可能性.再说了,std::vector在libstdc++有相应的模板参数Allocator,我可以指定__gnu_cxx::__mt_alloc为分配器.
我正在使用编写得很糟糕的代码库并且有很多内存泄漏.
它使用了许多包含原始指针的结构,这些结构主要用作动态数组.
尽管结构通常在函数之间传递,但是这些指针的分配和释放被放置在随机位置,并且不容易被跟踪/推理/理解.
我将其中的一些更改为类,并将这些指针改为由类本身进行RAII.它们运行良好并且看起来不是很难看,除了我禁止复制构造和复制分配这些类只是因为我不想花时间实现它们.
现在我在想,我是在重新发明轮子吗?为什么我不用std:array或std :: valarray替换C风格的数组?
我更喜欢std :: valarray,因为它使用堆内存和RAIIed.并且std :: array在我的开发环境中尚未可用.
Edit1:std :: array的另一个优点是大多数动态数组都是POD(主要是int16_t,int32_t和float)数组,而数字API可以使生活更轻松.
在我开始之前有什么需要注意的吗?
我能想到的是,可能没有一种简单的方法可以将std :: valarray或std :: array转换回C风格的数组,并且我们的部分代码确实使用指针算法并且需要将数据呈现为普通的C风格的数组.
还要别的吗?
编辑2
我最近遇到了这个问题.一个非常糟糕的事情std::valarray是它在C++ 11之前不能安全地复制 - 可分配.
正如在该答案中引用的那样,在C++ 03及更早版本中,如果源和目标具有不同的大小,则为UB.
如果我已经正确理解,由于C++ 11它一直安全只要同时调用一个容器的const成员函数和修改容器中的元素作为容器本身没有被修改作为操作的一部分(如从可见例如cppreference.com中有关线程安全的表格.由于std :: valarray没有在(草案)标准的容器部分列出,我不确定线程安全是否也适用于它.换一种说法,
我想使用std :: valarray作为使用多个线程填充的多维数字数组.
例如,赋值运算符std::slice_array:
void operator=(const valarray<T>&) const; //#1
void operator=(const T&) const; //#2
const slice_array& operator=(const slice_array&) const; //#3
Run Code Online (Sandbox Code Playgroud)
#1并#2返回void,但#3返回const slice_array&。
它禁止某些代码,例如:
std::valarray<int> va{1, 2, 3, 4, 5, 6};
va[std::slice(3, 2, 2)] = va[std::slice(0, 2, 2)] = va[0];
Run Code Online (Sandbox Code Playgroud)
为什么?