根据指针条件初始化std::vector

Conditionally initialize std::vector from pointer

本文关键字:std vector 初始化 条件 指针      更新时间:2023-10-16

我正在与一些C++代码接口,这些代码有一个提供指针和对象大小的方法(一些我无法更改的专有库(。界面看起来像这样:

float *arrayPtr();
int arraySize();

我有一个类需要将其复制到向量中(以便延长其寿命(。在这个指针不是nullptr的场景中,构造函数相当简单(我需要复制数据以延长其寿命(:

struct A {
std::vector<float> vec;
A(float *ptr, int size) : vec( ptr, std::next(ptr, size) ) {}
}

然而,当ptrnullptr时,我有点不确定如何最好地处理初始化。我可以默认初始化,然后将所有内容移动到构造函数主体,但这感觉效率很低:

A(float *ptr, int size) {
if (ptr) {
vec = std::vector<float>( ptr, std::next(ptr, size));
}
}

还有其他选择吗?

ptrnullptr时,我希望向量默认初始化为空向量。

编辑:

我突然想到我可能应该这么做:

A(float *ptr, int size) : vec( ptr ? std::vector<float>(ptr, std::next(ptr, size)) : std::vector<float>() ) {}

但也许还有更好的形式??

这不一定"更好"(实际上我认为你的原始代码很好,因为向量的默认初始化实际上没有任何成本(,但当你需要为初始化器执行一些逻辑时,你可以使用一个帮助函数:

struct A {
std::vector<float> vec;
A(float *ptr, int size) : vec( make_A_vector(ptr, size) ) {}
private:  
static std::vector<float> make_A_vector(float const *begin, int size)
{
if ( size < 0 || (size > 0 && !begin) )
throw std::runtime_error("invalid array length for A");
if ( size == 0 )
return {};
return std::vector<float>(begin, begin + size);
}
};

另一个常见的设计是保持类的简单性,并将构建逻辑完全放在一个自由函数中:

struct A
{
std::vector<float> vec;
};
inline A make_A(float const *ptr, int size)
{
// sanity check omitted for brevity
if ( size == 0 )
return A{};
return A{ std::vector<float>(ptr, ptr + size) };
}

这是一个基于经验的判断,关于什么是过度杀戮,什么是美学:(

研究std::nextstd::vector的ctor在做什么。你的第一次尝试效果很好。ONLY和ONLY如果您的size是可靠的0,当您的指针是nullptr时。

std::next(it, n)

it-迭代到基本位置。ForwardIterator应至少为前向迭代器。

n-偏移的元素位置数(默认为1(。这仅对随机访问和双向访问是负面的迭代器。difference_type是表示ForwardIterator类型的迭代器之间的距离。

如果你确信,你的给定大小是0,当你得到一个nullptr时,std::next会返回你的指针指向的相同位置。

std::vector

你使用这个ctor:

构建包含范围[第一个,最后一个(内容的容器。

如果firstlast相同,则会得到一个空的std::vector。所以nullptr从来都不是问题。


不管这些发现如何。您应该始终检查nullptr的。为了防御编程-所有输入都是邪恶的!


你提到过,你得到的库以容易出错而闻名。请给自己省去很多麻烦,并检查你从中得到的每个参数的完整性。


关于您担心您的实现会比另一个执行得更差的一条评论。在具有数千或数百万次迭代的loop中检查这些实现。然后,如果它影响到你,你可以做出预测。