C ++,如何正确复制std :: vector< Class *>在复制构造函数? [英] C++, how to correctly copy std::vector<Class *> in copy constructor?

查看:201
本文介绍了C ++,如何正确复制std :: vector< Class *>在复制构造函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用这两个类

 二进制数据
class A {
public:
A();
A(const A&);
〜A();
}

//主数据容器
class B {
public:
B();
B(const B&);
〜B();
protected:
std :: vector< A *>数据;
}

//复制类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 *它)));
}
}



我想这个类会做的工作,但我



最初:data() - 是这个初始化需要正确初始化空向量(它是编写一个好的和干净的代码的一部分)。



如何使用 vector :: iterator 在复制构造函数中,我发现的唯一方式是我写入代码(const应该是强制性的复制构造函数)。



复制只是向量会复制指针值而不是整个对象?



最后新数据初始化...有什么办法如何替换整个循环更小的代码段和/或有任何标准如何为包含对象指针的std ::容器写入复制构造函数



子问题: m假设使用向量< A *> 比各种原因更合适和有效,而不是向量< A> (不是每次复制,决定是否复制对象...)

解决方案

data()不是必需的,因为在输入构造函数之前将自动完成向量。您只需要初始化为没有默认构造函数(或引用,常量等)的POD类型或类型的成员。



您可以使用数字另一个具有的元素,使得向量不必在其生长时自行调整大小。如果你不这样做,你开始一个小的向量,并通过分配和重新分配增量达到目的地大小。这将使向量从一开始就是正确的大小:

  B :: B(const B& orig):data orig.data.size()){
for(std :: size_t i = 0; i data [i] = new A * orig.data [i]);
}

请注意,您并未使用 push_back 任何更多因为向量已经充满 orig.data.size()默认构造的元素数量( NULL



这也减少了代码,因为你可以使用整数来迭代它而不是迭代器。

如果您真的想使用迭代器,可以执行

  B :: B(const B& orig):data(orig.data.size()){
// auto在这里是首选,但我不知道你的编译器是否支持
vector& > :: iterator thisit = data.begin();
vector< A *> :: const_iterator thatit = orig.data.cbegin();

for(; thatit!= orig.data.cend(); ++ thisit,++ thatit)
* thisit = new A(** itit);
}

这样做的好处是它可以与其他容器类型code> list )通过更改迭代器的类型(但是,如果你有 auto / p>

如果要添加异常安全,您需要一个 try / catch 块:

  B :: B(const B& orig):data(orig.data.size()){
try {
// auto是最好的,但我不知道你的编译器是否支持
vector< A *> :: iterator thisit = data.begin();
vector< A *> :: const_iterator thatit = orig.data.cbegin();

for(; thatit!= orig.data.cend(); ++ thisit,++ thatit)
* thisit = new A(** itit);
} catch(...){
for(vector< A *> :: iterator i = data.begin(); i!= data.end(); ++ i)
if(!* i)
break;
else
delete * i;

throw;
}
}

这样你就不会有内存泄漏的 new 调用引发异常。当然你可以使用 try / catch 和没有迭代器的方式,如果你宁愿这样做。


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 it job, but I'm finding to way how to reach the total perfection in this.

At first :data() - is this initialization required to initialize empty vector correctly (and it's part of writing a good and clean code)?

How to use vector::iterator in copy constructor, the only way I found is the one I've written into code (const should be mandatory for copy constructor).

Copying just vector would copy just pointer values and not whole objects?

And finally new data initialization... Is there any way how could I replace the whole loop with smaller piece of code and/or is there any standard how to write copy constructor for std::containers which contains 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...)

解决方案

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 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 do that, 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:

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]);
}

Notice that you are not using push_back any more because the vector is already full of orig.data.size() number of elements that are default constructed (which is NULL 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

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);
}

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 have auto).

If you want to add exception-safety, you need a try/catch block:

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;
    }
}

This way you will not have a memory leak if one of the new calls throws an exception. Of course you can use the try/catch along with the way without iterators if you'd rather do it that way.

这篇关于C ++,如何正确复制std :: vector&lt; Class *&gt;在复制构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆