2016-12-28 12 views
8

Я просто знал std::enable_shared_from_this форму this link.
Но, прочитав приведенный ниже код, я не знаю, когда его использовать.
Когда мы должны использовать std :: enable_shared_from_this

try { 
     Good not_so_good; 
     std::shared_ptr<Good> gp1 = not_so_good.getptr(); 
    } catch(std::bad_weak_ptr& e) { 
     // undefined behavior (until C++17) and std::bad_weak_ptr thrown (since C++17) 
     std::cout << e.what() << '\n';  
    } 

Код выше «не так хорошо», потому что нет никакого существующего shared_ptr перед вызовом getptr(). Так что хорошая вещь должна быть:

std::shared_ptr<Good> gp1 = std::make_shared<Good>(); // having a shared_ptr at the beginning 
std::shared_ptr<Good> gp2 = gp1->getptr(); 

Однако, если я уже имел shared_ptr объект, то почему бы мне не просто код как это: std::shared_ptr<Good> gp2 = gp1;, а это означает, что мне не нужно std::enable_shared_from_this вообще.

На мой взгляд, используя std::enable_shared_from_this, чтобы убедиться, что более чем один shared_ptr объекты имеют один и тот же блок управления, так что мы можем избежать the double-delete problem. Но если я должен напомнить себе создать shared_ptr в начале. Почему бы мне просто не напомнить себе, что использовать объект shared_ptr для создания нового, вместо использования необработанного указателя?

+0

'void f (Хорошо & g);/* ... */f (* gp1);/* ... */void f (Good & g) {/ * теперь что? * /}' – milleniumbug

+0

@milleniumbug sorry I не понимают, что вы пытаетесь сказать. – Yves

+1

'f' не имеет доступа к' shared_ptr', так как он принимает ссылку, а не общий указатель. Иногда вы можете изменить, чтобы вместо этого была ссылка, но не для функций-членов - 'this' всегда является необработанным указателем. – milleniumbug

ответ

6

Подсказка о том, когда std::enable_shared_from_this<T> полезен в его названии: при получении объектов на основе некоторых запросов может потребоваться вернуть указатель на сам объект. Если результатом должно быть std::shared_ptr<T>, становится необходимым вернуть такой указатель изнутри функции-члена, где, как правило, нет std::shared_ptr<T>.

Имея производную от std::enable_shared_from_this<T>, вы можете получить std::shared_ptr<T> только указатель типа T. Это, однако, предположить, что объект уже управляется через std::shared_ptr<T> и это создало бы хаос, если объект выделяется в стеке:

struct S: std::enable_shared_from_this<S> { 
    std::shared_ptr<S> get_object() { 
     return this->shared_from_this(); 
    }; 
} 

int main() { 
    std::shared_ptr<S> ptr1 = std::make_shared<S>(); 
    std::shared_ptr<S> ptr2 = ptr1->get_object(); 
    // ... 
} 

В реалистичном сценарии есть, вероятно, некоторые условия, при которых std::shared_ptr<T> к текущему объекту.

2

Существует несколько вариантов использования, которые вы не можете использовать в шаблоне std::shared_ptr<T>, как непрозрачный указатель.

В этом случае полезно иметь это:

В some_file.cpp

struct A : std::enable_shared_from_this<A> {}; 

extern "C" void f_c(A*); 
extern "C" void f_cpp(A* a) { 
    std::shared_ptr<A> shared_a = a->shared_from_this(); 
    // work with operation requires shared_ptr 
} 

int main() 
{ 
    std::shared_ptr<A> a = std::make_shared<A>(); 
    f_c(a.get()); 
} 

В some_other.c

struct A; 
void f_cpp(struct A* a); 
void f_c(struct A* a) { 
    f_cpp(a); 
} 
+0

Я немного смущен, почему я должен использовать sharea_ptr для a в f_cpp? если f_cpp требовал, чтобы он принимал shared_ptr вместо raw pointef A *. – Gavin

2

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

class Number; 

class Expression : public std::enable_shared_from_this<Expression> 
{ 
public: 
    virtual std::shared_ptr<Number> evaluate() = 0; 
    virtual ~Expression() {} 
}; 

class Number : public Expression 
{ 
    int x; 
public: 
    int value() const { return x; } 
    std::shared_ptr<Number> evaluate() override 
    { 
     return std::static_pointer_cast<Number>(shared_from_this()); 
    } 
    Number(int x) : x(x) {} 
}; 

class Addition : public Expression 
{ 
    std::shared_ptr<Expression> left; 
    std::shared_ptr<Expression> right; 
public: 
    std::shared_ptr<Number> evaluate() override 
    { 
     int l = left->evaluate()->value(); 
     int r = right->evaluate()->value(); 
     return std::make_shared<Number>(l + r); 
    } 
    Addition(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right) : 
     left(left), 
     right(right) 
    { 

    } 
}; 

Live on Coliru

Обратите внимание, что «очевидный» способ реализации Number::evaluate() с return std::shared_ptr<Number>(this); нарушаются, поскольку это приведет к двойному удалению.

+0

Возвращаемый тип 'оценка' должен быть' std :: shared_ptr ', спасая вас от всех злых кастингов. –

+0

Вы забыли указать базовый класс 'Number' и' Addition'. – Oktalist

+0

@BenVoigt Да, в этом примере кода просто это делается. Моя программа имела разные типы, поэтому я изначально этого не делал. (также грустно, что я должен использовать бросок из 'std :: shared_from_this()', но я думаю, что это жизнь) – milleniumbug

 Смежные вопросы

  • Нет связанных вопросов^_^