Общий указатель из get () внутри блока - PullRequest
0 голосов
/ 14 марта 2019

У меня какая-то путаница со следующим фрагментом кода

    #include <iostream>
    #include <memory>

    using namespace std;

    int main()
    {

        int *iptr = new int(12); //create built-in pointer

        shared_ptr<int> s(iptr); //create shared pointer to it

        int *q = s.get();        //get built-in back using get (redundant step, but I was practicing)

        shared_ptr<int> (q); //Does NOT work without giving it a separate block ; error: conflicting declaration ‘std::shared_ptr q’ 

        //{shared_ptr<int> (q);} //This works!!

        return 0;
    }

Мой вопрос: почему один работает, а другой нет? Какое имя получает тот, который находится в блоке с областью действия? кажется, у него нет имени, если мы следуем следующему синтаксису [type name(args)]

Ответы [ 2 ]

3 голосов
/ 15 марта 2019

Проблема здесь не в общих указателях, вы просто неправильно истолковали свой собственный код.Строка:

shared_ptr<int> (q);

является , а не конструкцией анонимного shared_ptr<int> с использованием q в качестве аргумента конструктора.На самом деле это объявление с именем shared_ptr<int>.Вы действительно написали:

shared_ptr<int> q;

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

Также:

  • Вы должны избегать использования new напрямую.Вместо этого используйте std::make_shared<int>().
  • Никогда не передайте указатель на память, у которой есть другой владелец, конструктору std::shared_ptr<>, поскольку этот конструктор становится владельцем памяти, и будет предполагать, что может использовать ее, даже если эта память была освобождена первоначальным владельцем.
2 голосов
/ 15 марта 2019

Я сбился с пути, @einpoklum понял все правильно.


Вы не можете создать более одного shared_ptr из одного и того же обычного указателя. Все остальные shared_ptr должны быть копиями другого shared_ptr.

Это потому, что shared_ptr должен выделить другой объект, который поддерживает счетчик ссылок для вашего объекта, и это делает конструктор shared_ptr из простого простого указателя *1014*. shared_ptr конструкторы копирования просто увеличивают счетчик ссылок.

Когда вы создаете несколько shared_ptr с одного и того же указателя plain , они выделяют свои собственные счетчики ссылок и в конечном итоге удаляют ваш объект несколько раз. Что приводит к неопределенному поведению (часто происходит сбой при втором удалении).


Существует также boost::intrusive_ptr, который ожидает, что счетчик ссылок будет внутри объекта. Следовательно, несколько boost::intrusive_ptr могут быть созданы из одного и того же указателя plain , поскольку все они используют один и тот же счетчик ссылок внутри объекта.

boost::intrusive_ptr также более эффективен, чем shared_ptr, но не поддерживает слабые указатели.

boost::intrusive_ptr более эффективен, поскольку он имеет тот же размер, что и обычный указатель (размер shared_ptr в два раза больше), поскольку ему не нужно выделять отдельную структуру со счетчиком ссылок и объектом удаления в другом месте и держать еще один указатель на это.

В многопоточном приложении shared_ptr всегда использует более дорогой атомарный прирост / декремент для обслуживания счетчика ссылок, даже если вы никогда не передаете эти указатели через потоки. В хорошо спроектированном приложении только shared_ptr s для определенных T s когда-либо передаются через потоки, и только эти shared_ptr<T> s должны использовать атомный счетчик. С boost::intrusive_ptr вы используете атомарный счетчик только для объектов, которые передаются между потоками, и используете простой целочисленный счетчик для остальных ваших объектов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...