передать smart_pointer в конструктор против необработанного указателя - PullRequest
1 голос
/ 21 января 2011

Допустим, у меня есть полиморфный класс Structure, подобный этому

class Base
{
//some implementation
};

class Deriv: public Base
{
//implementation
}

class Case1
{
  boost::scoped_ptr<A> a_ //polymorphic data member owned by C
public:
  Case1(A* a):a_(a)
  {

  }
};
class Case2
{
  boost::scoped_ptr<A> a_ //polymorphic data member owned by C
public:
  Case2(std::auto_ptr<A> a):a_( a.release() )
  {

  }
};

И у меня есть третий класс case1 / 2, которому принадлежит один из тех полиморфных объектов, описанных выше.Теперь мне нужно передать указатель на объект Base / Deriv конструктору класса case1 / 2, который становится владельцем этого объекта.Должен ли я передать этот объект в качестве умного указателя, например, auto_ptr, чтобы прояснить, что я забочусь об этом объекте, или разрешить необработанные указатели (случай 1), чтобы позволить намного более простой синтаксис, такой как

Case1 c(new Deriv);
//compared to 
Case2 c(std::auto_ptr<Base>(new Deriv));

Ответы [ 3 ]

3 голосов
/ 21 января 2011

Вам нужно передать умный указатель и назвать его умным указателем (например, он не может быть временным):

std::auto_ptr<Base> p(new Deriv);
Case2 c(p); // this constructor would need to take the `auto_ptr` by reference 
            // so that it can steal ownership.

В вашем первом примере, Case1 c(new Deriv);, объектможет возникнуть утечка, если возникает исключение между выполнением new Deriv и моментом, когда объект Case1 становится его владельцем в конструкторе.

Во втором примере, где вы не называете умный указательобъект может быть утечка при некоторых обстоятельствах.В частности, это может произойти , если у вас есть более одного аргумента функции .

0 голосов
/ 21 января 2011

У меня нет источника для того, чтобы это было наилучшей практикой, но в целом, если вы собираетесь каким-либо образом хранить ресурс, я считаю, что лучше всего приобретать этот ресурс таким же образом.

Причина этого заключается в том, что в C ++ 0x копирование / перемещение выполняется при задании аргумента, затем вы просто перемещаете его в хранилище, например:

struct store_string
{
    store_string(std::string s) : // potentially free, copy if not
    s(std::move(s)) // free
    {}

    std::string s;
};

Или в C ++ 03, если ваш тип может быть дешево создан по умолчанию:

struct store_string
{
    store_string(std::string ss) // make necessary copy
    {
        s.swap(ss); // free
    }

    std::string s;
};

Так что для вас я бы сделал:

class Case2
{
    boost::scoped_ptr<A> a_ //polymorphic data member owned by C
public:
    Case2(boost::scoped_ptr<A>& aa)
    {
        a.swap(aa); // take resource
    }
};

Это упростит вам задачу и позволит клиенту точно знать, как будет осуществляться управление ресурсом.

0 голосов
/ 21 января 2011

Если ваш класс полностью владеет переданным ему объектом, то лучше всего сделать это явным путем использования auto_ptr во всех применимых случаях. Лучше всего использовать явное конструирование auto_ptr, поскольку оно гарантирует, что пользователь API знает, что вы владеете этим объектом, и снижает вероятность возникновения ошибок в владении.

Если у вашего класса есть владелец переменной, то обычно это делается путем предоставления необработанного указателя и функции уничтожения.

class best_practices {
    std::function<void(A*)> destructor;
    A* ptr;
public:
    best_practices(A* a, std::function<void(A*)> destructfunc)
        : ptr(a), destructor(destructfunc) {}
    ~best_practices() {
        destructor(ptr);
    }
};
...