我正在使用这两个类
// This is generic data structure containing some binary data
class A {
public:
A();
A(const A&);
~A();
}
// Main data container
class B {
public:
B();
B( const B&);
~B();
protected:
std::vector<A *> data;
}
// Copy constructor for class b
B::B( const B& orig):data() {
for( std::vector<A *>::const_iterator it = orig.data.begin();
it < orig.data.end(); ++it){
data.push_back( new A( *(*it)));
}
}
我想这堂课会做到这一点,但我发现如何达到完美的目标。
首先:data()
- 这是初始化空向量所需的初始化(这是编写一个好的和干净的代码的一部分)吗?
如何在复制构造函数中使用vector::iterator
,我找到的唯一方法就是我写入代码的方法(对于复制构造函数,const应该是必需的)。
只复制vector会复制指针值而不是整个对象吗?
最后新数据初始化......有什么办法可以用较小的代码替换整个循环和/或是否有任何标准如何为包含对象的std :: containers编写复制构造函数指针
子问题:我假设使用vector<A *>
比vector<A>
更加合适和有效,而不是每次都复制,决定是否(不)复制对象。 。)
答案 0 :(得分:10)
data()
不是必需的,因为在输入构造函数之前,它将自动完成到向量。您只需初始化POD类型的成员或没有默认构造函数(或引用,常量等)的成员。
您可以使用另一个元素的元素数量初始化向量,以便向量在增长时不必自行调整大小。如果你不这样做,你将从一个小向量开始,并通过分配和重新分配逐步达到目标大小。这将使矢量从一开始就具有正确的大小:
B::B(const B& orig) : data(orig.data.size()) {
for (std::size_t i = 0; i < orig.data.size(); ++i)
data[i] = new A(*orig.data[i]);
}
请注意,您不再使用push_back
因为向量已经填充了orig.data.size()
个默认构造的元素(在指针的情况下为NULL
)。
这也会减少代码,因为您可以使用整数来迭代代码而不是迭代器。
如果你真的想使用迭代器,你可以做
B::B(const B& orig) : data(orig.data.size()) {
// auto is preferable here but I don't know if your compiler supports it
vector<A*>::iterator thisit = data.begin();
vector<A*>::const_iterator thatit = orig.data.cbegin();
for (; thatit != orig.data.cend(); ++thisit, ++thatit)
*thisit = new A(**thatit);
}
这样做的好处是,只需更改迭代器的类型,它就可以与其他容器类型(如list
)一起使用(当然,如果你有auto
,它就会消失)。
如果要添加异常安全性,则需要try/catch
块:
B::B(const B& orig) : data(orig.data.size()) {
try {
// auto is preferable here but I don't know if your compiler supports it
vector<A*>::iterator thisit = data.begin();
vector<A*>::const_iterator thatit = orig.data.cbegin();
for (; thatit != orig.data.cend(); ++thisit, ++thatit)
*thisit = new A(**thatit);
} catch (...) {
for (vector<A*>::iterator i = data.begin(); i != data.end(); ++i)
if (!*i)
break;
else
delete *i;
throw;
}
}
这样,如果其中一个new
调用抛出异常,就不会有内存泄漏。当然你可以使用try/catch
以及没有迭代器的方式,如果你宁愿这样做的话。
答案 1 :(得分:0)
C++11 十年后,您应该能够利用其功能。
reserve()
预分配足够的空间并且仍然能够 push_back
或 emplace_back
,尽管对于普通指针来说这无关紧要。和 range-based for loop 以避免显式迭代器
B::B(const B &orig) {
data.reserve(orig.data.size());
for (auto p : orig.data)
data.push_back(new A(*p));
}
最后,您可以使用 std::unique_ptr
来确保安全并避免内存泄漏以及需要提供显式析构函数
class B {
public:
B();
B(const B&);
protected:
std::vector<std::unique_ptr<A> > data;
};
将构造函数更改为
B::B(const B &orig) {
data.reserve(orig.data.size());
for (auto &p : orig.data)
data.emplace_back(new A(*p));
}