如何创建结构向量并稍后初始化它们
Posted
技术标签:
【中文标题】如何创建结构向量并稍后初始化它们【英文标题】:How to create a vector of structs and initialize them later 【发布时间】:2014-11-28 10:57:42 【问题描述】:为了更容易处理,我想创建一个自定义元素的向量,之后我可以通过A[0]
等轻松访问。问题是每个元素都有一个非空的构造函数,即我不会写
elem A;
我必须写
elem A(int a, int b, int c);
在创建期间使用 a、b、c 固定值。但这对我来说是不可能的,因为我在运行时获取了这些元素的值。 那么,有没有办法做这样的事情:
Vector<elem> A;
elem B(int a, int b, int c);
A.push_back(B);
如果是,怎么做?
作为解释:Vector
可以是std::vector
或QVector
,但它们都会导致一个问题,要么在编译时崩溃,要么在运行时崩溃。
编辑:
完整代码:
#ifndef DPC_H
#define DPC_H
#include "../BlackLib/v2_0/BlackGPIO.h"
#include <QVector>
class DPC
private:
QVector<BlackLib::BlackGPIO> A;
public:
DPC();
~DPC();
;
#endif // DPC_H
#include "dpc.h"
DPC::DPC()
BlackLib::BlackGPIO Pin(BlackLib::BlackGPIO(BlackLib::GPIO_32, BlackLib::input));
/*DPC::A[0] = new */A.push_back(Pin);
A.push_back(Pin);
/*DPC::A[1] = new B*/A.push_back(BlackLib::BlackGPIO(BlackLib::GPIO_33, BlackLib::input));
BlackLib 是来自 https://github.com/yigityuce/BlackLib 的 BBB 引脚扩展的数据类型
解决方案:
使用std::vector<std::unique_ptr<BlackLib::BlackGPIO> > A;
【问题讨论】:
是的,我收到一条错误消息,告诉我“候选人需要 3 个参数,得到 0”。 在哪段代码中? 在Vector<elem> A;
这不应该要求 elem
是 DefaultConstructible。演示:ideone.com/159D9Q
这不是“完整代码”,见MCVE
【参考方案1】:
实际上,几乎完全按照您的写作方式。你可以这样做
#include <vector>
...
std::vector<B> A;
B foo(a, b, c);
A.push_back(foo);
或者,如果您有一个了解 C++11 的足够新的编译器,
#include <vector>
...
std::vector<B> A;
A.emplace_back(a, b, c);
后者保存一个副本(对象直接在向量内部构造),因此更好™。尽管正如@JonathanWakely 在 cmets 中指出的那样,必须注意维护 emplace_back
的异常安全性,因为
std::vector<std::unique_ptr<B> > vec;
vec.emplace_back(new B); // is not exception-safe if the vector has to
// relocate and might throw bad_alloc, in which case
// the newly allocated foo object is leaked because
// no one is responsible for cleaning it up.
vec.push_back(new B); // does not compile
这在std::vector<std::unique_ptr<...>>
的情况下很容易解决:
vec.emplace_back(std::make_unique<B>()); // C++14
vec.emplace_back(std::unique_ptr<B>(new B)); // C++11
// these also work and do the same thing with push_back
...但你必须记住这样做。
【讨论】:
我对 BlackLib 不熟悉,但粗略地看一下代码让我相信它不适合这个用例。 BlackGPIO 类拥有一个指向堆数据的裸指针,但没有用户定义的复制或移动构造函数。这后来导致双重释放。确实这应该在 BlackLib 中修复,但作为一种解决方法,您可以使用std::vector<std::unique_ptr<BlackLib::BlackGPIO> >
并执行 A.emplace_back(new BlackLib::BlackGPIO(...));
这意味着我必须添加自己的构造函数?
我之后是否必须释放一些东西(因为使用新的?)我对 unique_ptr 不太熟悉,因此我问(仅使用向量时我不必释放一些东西)。
std::unique_ptr
为您做到这一点——这是它在生活中的唯一目的。
@Wintermute, emplace_back(new ...)
如果向量尝试重新分配并抛出 bad_alloc
,则不是异常安全的@【参考方案2】:
那么,有没有办法做这样的事情:
vector<elem> A; elem B(int a, int b, int c); A.push_back(B);
如果是,怎么做?
是的。有几种可能性。首先,检查 emplace_back。类似于push back,只是参数直接传给了被持有对象的构造函数(完美转发):
vector<elem> A;
A.emplace_back(a, b, c); // for an existing elem::elem(int a, int b, int c)
你也可以依赖elem的拷贝构造函数,在一个模型之后构造n个元素:
elem model a, b, c ;
vector<elem> A 10, model ; // create 10 elements equal to model
【讨论】:
以上是关于如何创建结构向量并稍后初始化它们的主要内容,如果未能解决你的问题,请参考以下文章