C++ 作为类成员管理指针向量

C++ 作为类成员管理指针向量,c++,pointers,vector,C++,Pointers,Vector,我处于一个相当特殊的情况下,需要使用原始指针向量作为类成员: 我需要保留一个抽象对象的列表 我不能使用Boost或std::tr1,因此没有智能指针库(因为我使用的硬件的限制) 以下是我需要的基本示例: #include <vector> class Foo { virtual void foo() {} }; class Bar : public Foo { void foo(){} }; class FooBar { vector<Foo*

我处于一个相当特殊的情况下,需要使用原始指针向量作为类成员:

  • 我需要保留一个抽象对象的列表
  • 我不能使用Boost或std::tr1,因此没有智能指针库(因为我使用的硬件的限制)
以下是我需要的基本示例:

#include <vector>

class Foo
{
    virtual void foo() {}
};

class Bar : public Foo
{
    void foo(){}
};

class FooBar
{
    vector<Foo*> list;
    void add(){ list.push_back(new Bar()); }
};
顺便说一下,我想我还必须实现一个复制构造函数和赋值运算符。以下内容(基于和帖子)是否正确实施

FooBar::FooBar(const FooBar& orig) : list(orig.list.size()) {
    try {
        vector<Foo*>::iterator thisit = list.begin();
        vector<Foo*>::const_iterator thatit = orig.list.cbegin();

        for (; thatit != orig.list.cend(); ++thisit, ++thatit)
            *thisit = *thatit;  // I'm okay with a shallow copy

    } catch (...) {
        for (vector<Foo*>::iterator i = list.begin(); i != list.end(); ++i)
            if (!*i)
                break;
            else
                delete *i;

        throw;
    }
}

FooBar& operator=(const FooBar& orig){
    FooBar tmp(orig);
    swap(tmp);
    return *this;
}
FooBar::FooBar(const FooBar&orig):list(orig.list.size()){
试一试{
向量::迭代器thisit=list.begin();
vector::const_迭代器thatit=orig.list.cbegin();
for(;thatit!=orig.list.cend();++thisit,++thatit)
*thisit=*thattit;//我可以接受一份浅显的副本
}捕获(…){
对于(向量::迭代器i=list.begin();i!=list.end();++i)
如果(!*i)
打破
其他的
删除*i;
投掷;
}
}
FooBar和operator=(常量FooBar和orig){
FooBar tmp(原版);
掉期(tmp);
归还*这个;
}

据我所知,您的代码有一些主要缺陷。首先,您的第一个代码是正确的,是的,只要您的类拥有对象并且没有被复制,析构函数就会执行它应该执行的操作

此外,您的复制构造函数和赋值运算符看起来也有问题。首先,如果您可以进行浅层复制,那么您甚至不必编写函数,
std::vector
的复制构造函数和赋值运算符执行您手动完成的操作。我认为你不需要那个试抓块。顺便问一下,您的赋值运算符中的
交换的实现在哪里

出于您的目的,一个非常小的参考计数方案将起作用:

class FooPtr
{
     Foo* _raw;
     size_t* _ctl;

     FooPtr(Foo* ptr) : 
         _raw(ptr), _ctl(new size_t(0))
     {
     }

     template <class T>
     FooPtr(T* ptr) : FooPtr(static_cast<Foo*>(ptr)) {}

     FooPtr(const FooPtr& rhs) : 
         _raw(rhs._raw), _ctl(rhs._ctl)
     {
         ++(*_ctl);
     }

     ~FooPtr()
     {
        if (_raw == nullptr) return;
        --(*_ctl);
        if (*_ctl == 0)
        {
            delete _raw;
            delete _ctl;
        }
     }

     FooPtr& operator=(FooPtr ptr)
     {
         std::swap(*this, ptr);
         return *this;
     }

     Foo* operator->()
     {
         return _raw;
     }

     Foo& operator*()
     {
         return *_raw;
     }
}
class FooPtr
{
生食;
大小*;
FooPtr(Foo*ptr):
_原始(ptr),_-ctl(新尺寸_-t(0))
{
}
模板
FooPtr(T*ptr):FooPtr(static_cast(ptr)){}
FooPtr(const FooPtr&rhs):
_未加工(右侧未加工),未加工(右侧未加工)
{
++(*_ctl);
}
~FooPtr()
{
if(_raw==nullptr)返回;
--(*_ctl);
如果(*_ctl==0)
{
删除(未经加工);;
删除_ctl;
}
}
FooPtr&operator=(FooPtr-ptr)
{
标准::交换(*本,ptr);
归还*这个;
}
Foo*运算符->()
{
返回原材料;
}
Foo&操作员*()
{
返回*_原始;
}
}
您的类现在看起来是这样的,不需要析构函数、复制构造函数或赋值运算符:

class FooBar
{
     vector<FooPtr> list;
     void add(){ list.emplace_back(new Bar()); }
}
class FooBar
{
向量表;
void add(){list.emplace_back(新条());}
}

我写得很快,它可能包含bug,尽管它给出了我想的基本想法。此外,我还使用了一些c++11功能,如
emplace\u back
nullptr
,但它们可以很容易地转换为非11代码。

我将围绕
向量编写一个小包装,为您释放元素:

template<class Container>
void delete_elements(Container& cont) {
    typedef typename Container::reverse_iterator iterator;
    iterator end = container.rend();
    for (iterator i = container.rbegin(); end != i; ++i) {
        delete *i;
    }
}

struct deep_copy {
    template<typename T>
    T* operator()(T const* const other) {
        return other->clone();
    }
}

template<typename T>
struct ptr_vector {
    std::vector<T*> container;

    ptr_vector() { }

    ptr_vector(ptr_vector const& other) {
        std::vector<T*> tmp;
        tmp.reserve(other.container.size());

        try {
            std::transform(other.container.begin(), other.container.end(),
                    std::back_inserter(tmp), deep_copy());
        }
        catch (...) {
            (delete_elements)(tmp);
            throw;
        }

        container.swap(tmp);
    }

    ptr_vector& operator=(ptr_vector other) {
        container.swap(other.container);
        return *this;
    }

    ~ptr_vector() {
        (delete_elements)(container);
    }
};
模板
void delete_元素(容器和cont){
typedef typename容器::反向迭代器迭代器;
迭代器end=container.rend();
for(迭代器i=container.rbegin();end!=i;++i){
删除*i;
}
}
结构深拷贝{
模板
T*运算符()(T常量*常量其他){
返回其他->克隆();
}
}
模板
结构ptr_向量{
载体容器;
ptr_向量(){}
ptr_矢量(ptr_矢量常数和其他){
std::载体tmp;
tmp.reserve(other.container.size());
试一试{
std::transform(other.container.begin(),other.container.end(),
std::back_inserter(tmp),deep_copy();
}
捕获(…){
(删除要素)(tmp);
投掷;
}
集装箱互换(tmp);
}
ptr_向量和运算符=(ptr_向量其他){
容器交换(其他容器);
归还*这个;
}
~ptr_向量(){
(删除_元素)(容器);
}
};

现在您可以使用
ptr_vector v
v.container
添加元素。注意:您应该在基类中添加一个
clone
成员函数,以便在需要复制时不进行切片。

//我可以使用浅拷贝
,这与析构函数的实现一起会让您头疼。您将尝试释放多次分配。无法理解“无智能指针库”。您可以随时从智能指针获取原始指针。为什么要尝试/捕获?什么抛出?@πάνταῥεῖ, 那么析构函数是错误的还是复制构造函数是错误的呢?如果
没有智能指针库(由于我使用的硬件的限制)。
然后编写自己的简单共享智能指针,并计算链接数。这并不难。您当前的代码(复制方法)将泄漏内存库!我选择这个解决方案(尽管我是从@nik2016的链接开始实施的)。谢谢。我还没有测试过,但它看起来是个不错的选择。
template<class Container>
void delete_elements(Container& cont) {
    typedef typename Container::reverse_iterator iterator;
    iterator end = container.rend();
    for (iterator i = container.rbegin(); end != i; ++i) {
        delete *i;
    }
}

struct deep_copy {
    template<typename T>
    T* operator()(T const* const other) {
        return other->clone();
    }
}

template<typename T>
struct ptr_vector {
    std::vector<T*> container;

    ptr_vector() { }

    ptr_vector(ptr_vector const& other) {
        std::vector<T*> tmp;
        tmp.reserve(other.container.size());

        try {
            std::transform(other.container.begin(), other.container.end(),
                    std::back_inserter(tmp), deep_copy());
        }
        catch (...) {
            (delete_elements)(tmp);
            throw;
        }

        container.swap(tmp);
    }

    ptr_vector& operator=(ptr_vector other) {
        container.swap(other.container);
        return *this;
    }

    ~ptr_vector() {
        (delete_elements)(container);
    }
};