C++,如何正确复制std::vector在复制构造函数中?
我正在使用这两个类,
// 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 应该是强制的)。
复制向量是否复制指针值而不是整个对象?
最后是新数据初始化...有没有办法用更少的代码替换整个循环和/或是否有任何标准如何为包含对象指针的 std::containers 编写复制构造函数?
子问题:我假设使用 vector
出于各种原因比仅仅使用 vector
更合适和有效(不是每次都复制,功率决定是否(不)复制对象...)这个假设正确吗?
I'm using this two classes
// 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)));
}
}
I guess this class would do its job, but I'm looking for a way to reach total perfection.
First, :data()
- is this initialization required to initialize empty vector correctly (is it clean code)?
How is vector::iterator
used in copy constructor? The only way I found is the one I've written into code (const should be mandatory for copy constructor).
Does copying the vector copy pointer values and not whole objects?
And finally new data initialization... Is there any way to replace the whole loop with less code and/or is there any standard how to write copy constructor for std::containers which contain object pointers?
Sub question: I'm assuming using vector<A *>
is much more suitable and effective for various reasons than just vector<A>
(not copying every time, power to decide whether (not) to copy objects...) Is this assumption correct?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
data()
不是必需的,因为这将在输入构造函数之前自动对向量完成。您只需要初始化 POD(普通旧数据)类型或没有默认构造函数(或引用、常量等)的类型的成员。您可以使用另一个向量具有的元素数量来初始化向量,这样向量就不必在增长时调整自身大小。如果不这样做,您将从一个小向量开始,并通过分配和重新分配使其逐步达到目标大小。这将使向量从一开始就具有正确的大小:
请注意,您不再使用
push_back
因为向量已经充满了orig.data.size()
默认构造的元素数量(在指针的情况下为 NULL)。这也减少了代码,因为您可以使用整数而不是迭代器来迭代它。
如果你真的想使用迭代器,你可以这样做。
这样做的好处是,它只需更改迭代器的类型即可与其他容器类型(如
list
)一起使用(但当然,这会发生变化)如果您有auto
,请离开)。如果您想添加异常安全性,则需要一个
try/catch
块:这样,如果
new
调用之一引发异常,您就不会出现内存泄漏。当然,如果您愿意的话,可以将try/catch
与不使用迭代器的方式一起使用。The
data()
is not necessary because that will be done automatically to the vector before the constructor is entered. You only need to initialise members that are POD (plain old data) types or types which have no default constructor (or references, constants, etc).You can initialise the vector with the number of elements that the other one has, so that the vector doesn't have to resize itself as it grows. If you don't, you're starting with a small vector and making it incrementally reach the destination size via allocations and reallocations. This will make the vector the correct size from the very beginning:
Notice that you are not using
push_back
any more because the vector is already full oforig.data.size()
number of elements that are default constructed (which isNULL
in the case of pointers).This also trims down the code because you can use an integer to iterate it instead of an iterator.
If you really want to use iterators, you can do
The advantage of this is that it will work with other container types (like
list
) by just changing the types of the iterators (but of course that would go away if you haveauto
).If you want to add exception-safety, you need a
try/catch
block:This way you will not have a memory leak if one of the
new
calls throws an exception. Of course you can use thetry/catch
along with the way without iterators if you'd rather do it that way.C++11 十年后,您应该能够利用它的功能。
reserve()
预先分配足够的空间并且仍然能够push_back
或emplace_back
,尽管对于普通指针来说这并不重要。和基于范围的for循环以避免显式迭代器最后,你可以使用
std::unique_ptr
来安全并避免内存泄漏,并且需要提供显式析构函数,并将构造函数更改为
Ten years after C++11, you should be able to take advantage of its features.
reserve()
to preallocate enough room and still be able topush_back
oremplace_back
, though for plain pointers this doesn't matter. And range-based for loop to avoid explicit iteratorsAnd finally, you may use
std::unique_ptr
to be safe and avoid memory leaks and the need to provide an explicit destructorwith the constructor changing to