Що таке розумний покажчик і коли його слід використовувати?


1819

Що таке розумний покажчик і коли його слід використовувати?


7
Ознайомтесь із цим запитанням: <br> Smart Pointers: Або кому належить ваша дитина
Мартін Йорк

2
Зауважте, що реалізація std :: auto_ptr у Visual Studio 2005 жахливо порушена. <br> http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=98871 <br> http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101842 Використовуйте замість них.
Річард

25
Дві відмінні статті на цю тему: - Розумні покажчики - що, навіщо, що? - Гуру тижня №25
Lazer

1
Ось (безкоштовний) розділ Олександреску щодо ніткової зернистості створення розумних покажчиків різного смаку: informit.com/articles/article.aspx?p=31529 У своїй реалізації він використовує аргументи шаблону як "політики", щоб вказати, які атрибути він хоче ( наприклад, підрахунок посилань), тоді як стандартна бібліотека використовує окремі класи. Зауважте, що він також писав до появи посилань на rvalue, щоб зробити щось на зразок std :: unique_ptr можливим.
метал

Я хотів би додати ще одне питання до вищезазначеного питання, розумний вказівник std :: shared_ptr не має оператора підписки і не підтримує арифметику понтера, ми можемо використовувати get () для отримання вбудованого вказівника.
suresh m

Відповіді:


1883

ОНОВЛЕННЯ

Ця відповідь досить стара, і так описується те, що було «добре» в той час, які розумні вказівки надавали бібліотека Boost. Так як C ++ 11, стандартна бібліотека надала достатні типи смарт - покажчики, і тому ви повинні сприяти використанню std::unique_ptr, std::shared_ptrі std::weak_ptr.

Був також std::auto_ptr. Це дуже нагадувало масштабний покажчик, за винятком того, що він також мав "особливу" небезпечну здатність копіювати - що також несподівано передає право власності.
Він був застарілим у C ++ 11 та видалений у C ++ 17 , тому не слід його використовувати.

std::auto_ptr<MyObject> p1 (new MyObject());
std::auto_ptr<MyObject> p2 = p1; // Copy and transfer ownership. 
                                 // p1 gets set to empty!
p2->DoSomething(); // Works.
p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.

СТАРИЙ ВІДПОВІДЬ

Розумний вказівник - це клас, який обертає "сирий" (або "голий") покажчик C ++, щоб керувати терміном експлуатації об'єкта, на який вказують. Єдиного типу інтелектуального вказівника не існує, але всі вони намагаються практичним способом абстрагувати необроблений покажчик.

Інтелектуальні покажчики слід віддавати перевагу над необробленими покажчиками. Якщо вам здається, що вам потрібно використовувати вказівники (спершу подумайте, чи справді ви це робите), ви зазвичай хочете скористатися розумним вказівником, оскільки це може полегшити багато проблем із необробленими вказівниками, в основному забувши видалити об'єкт і витік пам'яті.

За допомогою необроблених покажчиків програміст повинен явно знищити об'єкт, коли він більше не корисний.

// Need to create the object to achieve some goal
MyObject* ptr = new MyObject(); 
ptr->DoSomething(); // Use the object in some way
delete ptr; // Destroy the object. Done with it.
// Wait, what if DoSomething() raises an exception...?

Розумний вказівник для порівняння визначає політику щодо знищення об'єкта. Вам все одно доведеться створити об’єкт, але вам більше не доведеться турбуватися про його знищення.

SomeSmartPtr<MyObject> ptr(new MyObject());
ptr->DoSomething(); // Use the object in some way.

// Destruction of the object happens, depending 
// on the policy the smart pointer class uses.

// Destruction would happen even if DoSomething() 
// raises an exception

Найпростіша застосовувана політика передбачає сферу використання об'єкта для обгортки інтелектуального вказівника, такого як реалізований boost::scoped_ptrабо std::unique_ptr.

void f()
{
    {
       std::unique_ptr<MyObject> ptr(new MyObject());
       ptr->DoSomethingUseful();
    } // ptr goes out of scope -- 
      // the MyObject is automatically destroyed.

    // ptr->Oops(); // Compile error: "ptr" not defined
                    // since it is no longer in scope.
}

Зауважте, що std::unique_ptrекземпляри неможливо скопіювати. Це запобігає видаленню вказівника кілька разів (неправильно). Однак ви можете передавати посилання на інші функції, які ви викликаєте.

std::unique_ptrs корисні, коли ви хочете прив’язати термін експлуатації об'єкта до певного блоку коду, або якщо ви вбудували його як дані члена всередині іншого об'єкта, термін служби цього іншого об'єкта. Об'єкт існує до тих пір, поки не містить блоку коду або до його знищення.

Більш складна політика інтелектуального вказівника передбачає підрахунок посилань. Це дозволяє скопіювати покажчик. Коли остання "посилання" на об'єкт знищена, об'єкт видаляється. Цю політику реалізує boost::shared_ptrта std::shared_ptr.

void f()
{
    typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias
    MyObjectPtr p1; // Empty

    {
        MyObjectPtr p2(new MyObject());
        // There is now one "reference" to the created object
        p1 = p2; // Copy the pointer.
        // There are now two references to the object.
    } // p2 is destroyed, leaving one reference to the object.
} // p1 is destroyed, leaving a reference count of zero. 
  // The object is deleted.

Довідкові підрахунки покажчиків дуже корисні, коли термін експлуатації вашого об'єкта значно складніший і не прив’язаний безпосередньо до певного розділу коду чи іншого об’єкта.

Є один недолік посилальних підрахунків покажчиків - можливість створення звисаючої посилання:

// Create the smart pointer on the heap
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
// Hmm, we forgot to destroy the smart pointer,
// because of that, the object is never destroyed!

Ще одна можливість створення кругових посилань:

struct Owner {
   std::shared_ptr<Owner> other;
};

std::shared_ptr<Owner> p1 (new Owner());
std::shared_ptr<Owner> p2 (new Owner());
p1->other = p2; // p1 references p2
p2->other = p1; // p2 references p1

// Oops, the reference count of of p1 and p2 never goes to zero!
// The objects are never destroyed!

Щоб вирішити цю проблему, і Boost, і C ++ 11 визначили a, weak_ptrщоб визначити слабке (незліченне) посилання на a shared_ptr.


7
Ви маєте на увазі std::auto_ptr<MyObject> p1 (new MyObject());замість std::auto_ptr<MyObject> p1 (new Owner());?
Mateen Ulhaq

35
Дивовижна відповідь. Було б непогано, якби його оновлювали для c ++ 11. Я знайшов цю відповідь, шукаючи інформацію про новий 11 стандарт, і було б добре, якби майбутні відвідувачі могли знайти оновлену інформацію. Я знаю, що функція auto_ptr застаріла. Я вважаю, що shated_ptr та slab_ptr існують як описано, і я думаю, що Scoped_ptr зараз є унікальним_ptr у стандарті. Якщо це правда, чи можна оновити цю відповідь?
SaulBack

16
Сказати, що можливість створення звисаючої посилання є недоліком посилальних підрахованих покажчиків, абсолютно божевільно. Можливі звисаючі посилання є недоліком будь-якого вказівника C ++ . Насправді це саме той недолік, який розумні покажчики мають на меті полегшити .
Майкл Дорст

16
Якщо ви оголосили покажчик на розумний вказівник (як це було зроблено в прикладі), ви свідомо відмовляєтесь від усіх переваг розумного вказівника. Це не є недоліком або недоліком дизайну, це найбільш ідіотичне використання.
Майкл Дорст

3
A const std::auto_ptrбезпечний у використанні, якщо ви застрягли з C ++ 03. Я досить широко використовував його для шаблону pimpl, поки не отримав доступ до C ++ 11.
Toby Speight

302

Ось простий варіант відповіді сучасних C ++ (C ++ 11 і пізніших версій):

  • Що таке розумний покажчик?
    Це тип, значення якого можна використовувати як вказівники, але який забезпечує додаткову функцію автоматичного управління пам'яттю: Коли розумний вказівник більше не використовується, пам'ять, на яку він вказує, розміщується (див. Також більш детальне визначення у Вікіпедії ).
  • Коли я повинен використовувати його?
    У коді, який включає відстеження права власності на фрагмент пам'яті, виділення або дерозміщення; розумний вказівник часто економить вам необхідність робити це явно.
  • Але який розумний вказівник я повинен використовувати в якому з цих випадків?
    • Використовуйте, std::unique_ptrколи ви не маєте наміру містити кілька посилань на один і той же об’єкт. Наприклад, використовуйте його для вказівника на пам'ять, який виділяється при введенні деякої області та де-розподілений при виході з області дії.
    • Використовуйте, std::shared_ptrколи ви хочете посилатись на ваш об'єкт з декількох місць - і не хочете, щоб ваш об’єкт не був виділений, поки всі ці посилання самі не зникнуть.
    • Використовуйте, std::weak_ptrколи ви хочете посилатись на ваш об'єкт з декількох місць - для тих посилань, для яких нормально ігнорувати та розміщувати місця (так що вони просто зауважать, що об'єкт відсутній, коли ви намагаєтесь знешкодити).
    • Не використовуйте boost::смарт-покажчики, std::auto_ptrза винятком випадків, коли це потрібно прочитати.
  • Гей, я не запитував, який з них використовувати!
    Ах, але ти дуже хотів, визнай це.
  • Тож коли я повинен використовувати звичайні покажчики тоді?
    Переважно в коді, який не враховує право власності на пам'ять. Це, як правило, у функціях, які отримують вказівник з іншого місця та не виділяють і не виділяють, а також не зберігають копію вказівника, що завищує їх виконання.

5
Варто зазначити, що, хоча розумні (володіють) покажчики допомагають при належному управлінні пам’яттю, необроблені (невласні) покажчики все ще корисні для інших організаційних цілей у структурах даних. Герб Саттер виступив із чудовою презентацією з цього приводу на CppCon 2016, яку ви можете побачити на YouTube: Стік свободи в C ++ ... За замовчуванням.
wiktor.wandachowicz

1
@ wiktor.wandachowicz T*- це std::unique_ptr<T>що std::weak_ptr<T>робитиstd::shared_ptr<T>
Caleth

@Caleth: Ні, я б не сказав цього.
einpoklum

1
@TonyTannous: З повагою - це була основна редакція; і я не відчуваю, що моя відповідь, яка є абстрактною, потребує цього. Я пропоную вам зробити приклад окремою відповіддю, за посиланням на нього в коментарі.
einpoklum

112

Розумний вказівник - це тип, що нагадує вказівник, з деякими додатковими функціональними можливостями, наприклад, автоматичним розміщенням пам'яті, підрахунком посилань тощо.

Невеликий вступ доступний на сторінці Smart покажчики - що, навіщо, що? .

Одним із простих типів смарт-покажчика є std::auto_ptr(глава 20.4.5 стандарту C ++), який дозволяє автоматично розміщувати пам'ять, коли вона виходить за межі, і яка є більш надійною, ніж просто використання покажчика, коли викиди викидів, хоча і менш гнучкі.

Ще одним зручним типом є те, boost::shared_ptrщо реалізує підрахунок посилань і автоматично передає пам'ять, коли не залишається посилання на об'єкт. Це допомагає уникнути витоку пам'яті та простий у використанні для реалізації RAII .

Тема глибоко висвітлена у книзі "Шаблони C ++: Повний посібник" Девіда Вандевурде, Ніколая М. Йосуттіса , глава 20. Розумні покажчики. Деякі теми висвітлювались:


2
Попередження std::auto_ptrзастаріле і сильно перешкоджає, оскільки ви можете випадково передати право власності. - C ++ 11 знімає необхідність Boost, використання: std::unique_ptr, std::shared_ptrіstd::weak_ptr
ninMonkey

42

Визначення, які дають Кріс, Сергдев та Ллойд, є правильними. Я віддаю перевагу більш простому визначенню, щоб просто зробити своє життя простим: Розумний покажчик - це просто клас, який перевантажує -> і *операторів. Це означає , що ваш об'єкт семантично виглядає як покажчик , але ви можете зробити це робити крутіше речі, включаючи підрахунок посилань, автоматичне знищення і т.д. , shared_ptrі auto_ptrдосить в більшості випадків, але приходьте разом зі своїм власним набором маленької ідіосинкразії.


30

Розумний вказівник - це як звичайний (набраний) вказівник, як "char *", за винятком випадків, коли сам вказівник виходить за межі, а також видаляється те, на що він вказує. Ви можете використовувати його як звичайний покажчик, використовуючи "->", але не, якщо вам потрібен фактичний вказівник на дані. Для цього можна використовувати "& * ptr".

Це корисно для:

  • Об'єкти, які повинні бути виділені новими, але які ви хочете мати такий самий термін експлуатації, як і щось у цій стеці. Якщо об'єкт призначений для інтелектуального вказівника, він буде видалений, коли програма закриє цю функцію / блок.

  • Дані членів класів, так що при видаленні об'єкта всі дані, що належать, також видаляються без спеціального коду в деструкторі (вам потрібно буде бути впевненим, що деструктор віртуальний, що майже завжди добре робити) .

Можливо, ви не хочете використовувати смарт-покажчик, коли:

  • ... покажчик фактично не повинен володіти даними ... тобто, коли ви просто використовуєте дані, але ви хочете, щоб вони пережили функцію, де ви посилаєтесь на них.
  • ... розумний вказівник не буде знищений в якийсь момент. Ви не хочете, щоб він знаходився в пам'яті, яка ніколи не руйнується (наприклад, в об'єкті, який динамічно виділяється, але не буде явно видалений).
  • ... два розумні покажчики можуть вказувати на однакові дані. (Однак, є навіть розумніші вказівники, які впораються з цим ... що називається підрахунком посилань .)

Дивись також:


18

Більшість видів розумних покажчиків обробляють розпорядження вказівником для вас. Це дуже зручно, оскільки вам більше не потрібно думати про утилізацію предметів вручну.

Інтелектуальні покажчики, що найчастіше використовуються, - це std::tr1::shared_ptr(або boost::shared_ptr), а рідше - std::auto_ptr. Я рекомендую регулярне використання shared_ptr.

shared_ptrдуже універсальний і стосується великої кількості різноманітних сценаріїв розпорядження, включаючи випадки, коли об’єкти потрібно "передавати через межі DLL" (звичайний випадок кошмару, якщо libcміж вашим кодом та DLL використовуються різні s).


18

Розумний вказівник - це об'єкт, який діє як вказівник, але додатково забезпечує контроль над побудовою, знищенням, копіюванням, переміщенням та перенаправленням.

Можна реалізувати власний інтелектуальний вказівник, але багато бібліотек також забезпечують реалізацію розумних покажчиків, кожна з яких має різні переваги та недоліки.

Наприклад, Boost забезпечує такі реалізації інтелектуального вказівника:

  • shared_ptr<T>є вказівником на Tвикористання опорного підрахунку для визначення, коли об'єкт більше не потрібен.
  • scoped_ptr<T>- покажчик автоматично видаляється, коли він виходить за межі області. Призначення неможливо.
  • intrusive_ptr<T>є ще одним покажчиком підрахунку опор. Він забезпечує більш високу продуктивність, ніж shared_ptrвимагає, але тип Tповинен забезпечити власний механізм підрахунку опор.
  • weak_ptr<T>є слабким покажчиком, який працює в поєднанні з тим, shared_ptrщоб уникнути кругових посилань.
  • shared_array<T>як shared_ptr, але для масивів T.
  • scoped_array<T>як scoped_ptr, але для масивів T.

Це лише один лінійний опис кожного з них і може бути використаний у міру потреби, для подальшої деталізації та прикладів можна переглянути документацію Boost.

Крім того, стандартна бібліотека C ++ забезпечує три розумні покажчики; std::unique_ptrза унікальну власність, std::shared_ptrдля спільної власності та std::weak_ptr. std::auto_ptrіснувало в C ++ 03, але зараз застаріле.


Поясніть, будь ласка, чому scoped_ptrце не так, як оголошено на місцях const unique_ptr- яке також видаляється при виході з області дії.
einpoklum

11

Ось посилання на подібні відповіді: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

Розумний вказівник - це об'єкт, який діє, виглядає і виглядає як звичайний покажчик, але пропонує більше функціональних можливостей. У C ++ інтелектуальні покажчики реалізовані як шаблонні класи, які інкапсулюють покажчик та переосмислюють стандартні оператори вказівників. Вони мають ряд переваг перед звичайними покажчиками. Вони гарантовано ініціалізуються як нульові покажчики або покажчики на купу об'єкта. Перевіряється непрямий показник через нульовий покажчик. Видалення ніколи не потрібно. Об'єкти автоматично звільняються, коли останній вказівник на них відійшов. Важливою проблемою цих розумних покажчиків є те, що на відміну від звичайних покажчиків вони не поважають спадщину. Інтелектуальні покажчики непривабливі для поліморфного коду. Наведене нижче - приклад для здійснення інтелектуальних покажчиків.

Приклад:

template <class X>
class smart_pointer
{
          public:
               smart_pointer();                          // makes a null pointer
               smart_pointer(const X& x)            // makes pointer to copy of x

               X& operator *( );
               const X& operator*( ) const;
               X* operator->() const;

               smart_pointer(const smart_pointer <X> &);
               const smart_pointer <X> & operator =(const smart_pointer<X>&);
               ~smart_pointer();
          private:
               //...
};

Цей клас реалізує розумний вказівник на об’єкт типу X. Сам об’єкт розташований на купі. Ось як його використовувати:

smart_pointer <employee> p= employee("Harris",1333);

Як і інші перевантажені оператори, p поводитиметься як звичайний покажчик,

cout<<*p;
p->raise_salary(0.5);

9

http://en.wikipedia.org/wiki/Smart_pointer

В інформатиці розумний покажчик - це абстрактний тип даних, який імітує вказівник, надаючи додаткові функції, такі як автоматичне збирання сміття або перевірка меж. Ці додаткові функції призначені для зменшення помилок, викликаних неправильним використанням покажчиків, зберігаючи ефективність. Інтелектуальні покажчики зазвичай відслідковують об'єкти, які вказують на них з метою управління пам'яттю. Неправильне використання покажчиків є головним джерелом помилок: постійне розподілення, розміщення та посилання, яке повинно виконувати програма, написана за допомогою покажчиків, робить великою ймовірністю виникнення деяких витоків пам'яті. Розумні вказівники намагаються запобігти витоку пам’яті, зробивши розподіл ресурсів автоматичним: коли вказівник на об’єкт (або останній у ряді покажчиків) знищений,


6

Нехай Т є класом у цьому підручнику Покажчики на C ++ можна розділити на 3 типи:

1) Сирі покажчики :

T a;  
T * _ptr = &a; 

Вони зберігають адресу пам'яті до місця в пам'яті. Використовуйте обережно, оскільки програми стають складними, важко відстежувати.

Покажчики даних про const або адресу {Читайте назад}

T a ; 
const T * ptr1 = &a ; 
T const * ptr1 = &a ;

Вказівник на тип даних T, який є const. Значить, ви не можете змінити тип даних за допомогою вказівника. тобто *ptr1 = 19; не вийде. Але ви можете перемістити вказівник. тобто ptr1++ , ptr1--; і т.д. буде працювати. Читання назад: вказівник на тип T, який є const

  T * const ptr2 ;

Вказівник const на тип даних T. Значить, ви не можете перемістити вказівник, але ви можете змінити значення, на яке вказує вказівник. тобто *ptr2 = 19буде працювати, але ptr2++ ; ptr2--і т.д. не буде працювати. Читання назад: вказівник const на тип T

const T * const ptr3 ; 

Вказівник const на тип даних const T. Значить, ви не можете або перемістити вказівник, ні ви можете змінити вказівник типу даних, який буде вказівником. тобто. ptr3-- ; ptr3++ ; *ptr3 = 19;не вийде

3) Розумні покажчики : { #include <memory>}

Спільний вказівник :

  T a ; 
     //shared_ptr<T> shptr(new T) ; not recommended but works 
     shared_ptr<T> shptr = make_shared<T>(); // faster + exception safe

     std::cout << shptr.use_count() ; // 1 //  gives the number of " 
things " pointing to it. 
     T * temp = shptr.get(); // gives a pointer to object

     // shared_pointer used like a regular pointer to call member functions
      shptr->memFn();
     (*shptr).memFn(); 

    //
     shptr.reset() ; // frees the object pointed to be the ptr 
     shptr = nullptr ; // frees the object 
     shptr = make_shared<T>() ; // frees the original object and points to new object

Реалізовано за допомогою підрахунку посилань, щоб відстежувати, скільки "речей" вказують на об'єкт, на який вказує вказівник. Коли цей підрахунок переходить до 0, об'єкт автоматично видаляється, тобто об’єкт видаляється, коли весь share_ptr, що вказує на об'єкт, виходить за межі області. Це позбавляється від головного болю від необхідності видалення об'єктів, які ви виділили за допомогою нових.

Слабкий вказівник: допомагає розібратися з циклічним посиланням, яке виникає при використанні Спільного вказівника Якщо у вас є два об'єкти, на які вказують два спільних вказівника, і є внутрішній загальний покажчик, що вказує один на одного спільним покажчиком, тоді буде циклічне посилання, і об'єкт не буде буде видалено, коли спільні покажчики виходять із сфери застосування. Щоб вирішити це, змініть внутрішній член з shared_ptr на slab_ptr. Примітка. Для доступу до елемента, на який вказує слабкий покажчик, використовуйте lock (), це повертає слабкий_ptr.

T a ; 
shared_ptr<T> shr = make_shared<T>() ; 
weak_ptr<T> wk = shr ; // initialize a weak_ptr from a shared_ptr 
wk.lock()->memFn() ; // use lock to get a shared_ptr 
//   ^^^ Can lead to exception if the shared ptr has gone out of scope
if(!wk.expired()) wk.lock()->memFn() ;
// Check if shared ptr has gone out of scope before access

Дивіться: Коли корисний std :: слаб_ptr?

Унікальний покажчик: Легкий розумний покажчик з ексклюзивним правом власності. Використовуйте, коли вказівник вказує на унікальні об’єкти, не ділячись об'єктами між покажчиками.

unique_ptr<T> uptr(new T);
uptr->memFn(); 

//T * ptr = uptr.release(); // uptr becomes null and object is pointed to by ptr
uptr.reset() ; // deletes the object pointed to by uptr 

Щоб змінити об'єкт, на який вказує унікальний ptr, використовуйте семантику переміщення

unique_ptr<T> uptr1(new T);
unique_ptr<T> uptr2(new T);
uptr2 = std::move(uptr1); 
// object pointed by uptr2 is deleted and 
// object pointed by uptr1 is pointed to by uptr2
// uptr1 becomes null 

Посилання: Вони по суті можуть бути хоч як покажчиками const, тобто покажчиком, який є const і не може бути переміщений з кращим синтаксисом.

Див.: Які відмінності між змінною вказівника та еталонною змінною в C ++?

r-value reference : reference to a temporary object   
l-value reference : reference to an object whose address can be obtained
const reference : reference to a data type which is const and cannot be modified 

Довідка: https://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQ Дякую Андре, що вказав на це питання.


3

Розумний покажчик - це клас, обгортка звичайного вказівника. На відміну від звичайних покажчиків, життєвий коло розумної точки базується на еталонному підрахунку (скільки часу присвоюється об'єкту інтелектуального вказівника). Отож, коли інтелектуальний покажчик присвоюється іншому, внутрішній відлік посилань плюс плюс. І кожного разу, коли об’єкт виходить за межі області, відлік посилань мінус мінус.

Автоматичний покажчик, хоч і схожий, абсолютно відрізняється від розумного вказівника. Це зручний клас, який передає ресурс кожного разу, коли автоматичний об'єкт вказівника виходить із змінної області. Певною мірою це змушує вказівник (на динамічно розподілену пам'ять) працює аналогічно змінній стеку (статично розподіляється під час компіляції).


2

Інтелектуальні покажчики - це ті, де вам не потрібно турбуватися про розподіл пам’яті, обмін ресурсами та передачу.

Ви можете дуже добре використовувати цей покажчик так само, як і будь-який розподіл працює на Java. У java Garbage Collector робить трюк, тоді як у Smart Pointers фокус роблять Destructors.


1

Існуючі відповіді хороші, але не висвітлюють, що робити, коли розумний покажчик не є (повною) відповіддю на проблему, яку ви намагаєтеся вирішити.

Крім усього іншого (що добре пояснено в інших відповідях), використання розумного вказівника є можливим рішенням Як використовувати абстрактний клас як тип повернення функції? що було позначено як дублікат цього питання. Однак першим питанням, яке потрібно задати, чи спокушається вказати абстрактний (або насправді будь-який) базовий клас як тип повернення в C ++, - це "що ти насправді маєш на увазі?". Існує хороша дискусія (з подальшими посиланнями) ідіоматичного об'єктно-орієнтованого програмування в C ++ (і як це відрізняється від інших мов) в документації бібліотеки контейнерів збільшити покажчик. Підсумовуючи, у C ++ ви повинні думати про право власності. Які розумні покажчики допомагають вам, але не є єдиним рішенням або завжди повноцінним рішенням (вони не дають вам поліморфної копії) і не завжди є рішенням, яке ви хочете викрити у своєму інтерфейсі (а повернення функції звучить жахливо багато як інтерфейс). Наприклад, може бути достатньо повернути посилання. Але у всіх цих випадках (розумний вказівник, контейнер вказівника або просто повернення посилання) ви змінили повернення зі значення на якусь форму посилання . Якщо вам дійсно потрібна копія, можливо, вам доведеться додати більше " idiom" на шаблоні або перейти за межі ідіоматичного (або іншим чином) OOP в C ++ до більш загального поліморфізму за допомогою бібліотек, таких як Adobe Poly або Boost.TypeErasure.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.