Что является потенциальными опасностями при использовании повышения:: shared_ptr?

Поскольку у вас нет требований, что сами четные и нечетные числа должны быть упорядочены в их соответственно половине массива, вы можете просто назначить их соответствующей части массива при вводе. Поэтому вам просто нужно использовать две «встречные» переменные: одну для левой, которая начинается с нуля и увеличивается, а другую для правой, которая начинается с длины вашего массива минус один и уменьшается. Затем вы можете добавить свои номера, проверив, если кто-то еще добавить, назначьте его с увеличенным вашим счетчиком левого поста, и если один нечетный, назначьте его с уменьшенным вашим правым постом. Делайте это в цикле, пока ваш левый счетчик не станет больше вашего правого счетчика. Я создал простой пример, в котором я не проверял NumberFormatException при разборе строки на int:

import java.util.Arrays;
import java.util.Scanner;

public class SortedArrayInput {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Enter length of array: ");
        final int arrayLength = Integer.parseInt(scanner.nextLine());

        int intArray[] = new int[arrayLength];
        for (int l = 0, r = arrayLength - 1; l <= r; ) {
            System.out.print("Enter new array value: ");
            int v = Integer.parseInt(scanner.nextLine());
            intArray[v % 2 == 0 ? l++ : r--] = v;
        }

        System.out.println("Output: " + Arrays.toString(intArray));
    }
}

Пример ввода / вывода:

Enter length of array: 6
Enter new array value: 1
Enter new array value: 2
Enter new array value: 3
Enter new array value: 4
Enter new array value: 5
Enter new array value: 6
Output: [2, 4, 6, 5, 3, 1]
49
задан ThiefMaster 17 August 2014 в 04:01
поделиться

12 ответов

Циклические ссылки: a shared_ptr<> к чему-то, что имеет a shared_ptr<> к исходному объекту. Можно использовать weak_ptr<> повредить этот цикл, конечно.


Я добавляю следующее как пример того, о чем я говорю в комментариях.

class node : public enable_shared_from_this<node> {
public :
    void set_parent(shared_ptr<node> parent) { parent_ = parent; }
    void add_child(shared_ptr<node> child) {
        children_.push_back(child);
        child->set_parent(shared_from_this());
    }

    void frob() {
        do_frob();
        if (parent_) parent_->frob();
    }

private :
    void do_frob();
    shared_ptr<node> parent_;
    vector< shared_ptr<node> > children_;
};

В этом примере у Вас есть дерево узлов, каждый из которых содержит указатель на своего родителя. frob () функция членства, по любой причине, слегка колеблется вверх через дерево. (Это является не совсем диковинным; некоторые платформы GUI прокладывают себе путь).

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

class node : public enable_shared_from_this<node> {
public :
    void set_parent(shared_ptr<node> parent) { parent_ = parent; }
    void add_child(shared_ptr<node> child) {
        children_.push_back(child);
        child->set_parent(shared_from_this());
    }

    void frob() {
        do_frob();
        shared_ptr<node> parent = parent_.lock(); // Note: parent_.lock()
        if (parent) parent->frob();
    }

private :
    void do_frob();
    weak_ptr<node> parent_; // Note: now a weak_ptr<>
    vector< shared_ptr<node> > children_;
};

Здесь, родительский узел был заменен слабым указателем. Это больше не имеет мнение во время жизни узла, к которому это относится. Таким образом, если самый верхний узел выходит из объема как в предыдущем примере, то, в то время как он содержит сильные ссылки своим детям, его дети не держат сильные ссылки к своим родителям. Таким образом нет никаких сильных ссылок к объекту, и он моется. В свою очередь это заставляет детей терять свою одну сильную ссылку, которая заставляет их мыться и так далее. Короче говоря, эта утечка привычки. И только путем стратегической замены shared_ptr <> с weak_ptr <>.

Примечание: Вышеупомянутое применяется одинаково к станд.:: shared_ptr <> и станд.:: weak_ptr <>, как это делает для повышения:: shared_ptr <> и повышение:: weak_ptr <>.

42
ответ дан Kaz Dragon 7 November 2019 в 11:28
поделиться

Мы отлаживаем несколько недель странное поведение.

Причина была:
мы передали 'это' некоторым рабочим потока вместо 'shared_from_this'.

10
ответ дан Mykola Golubyev 7 November 2019 в 11:28
поделиться

Вот две вещи избежать:

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

  • Передача ссылки или необработанного указателя на a shared_ptr должно быть опасным также, так как это не увеличит внутреннее количество, которое помогает поддержать объект.

12
ответ дан Frank 7 November 2019 в 11:28
поделиться

Создание нескольких не связанных shared_ptrк тому же объекту:

#include <stdio.h>
#include "boost/shared_ptr.hpp"

class foo
{
public:
    foo() { printf( "foo()\n"); }

    ~foo() { printf( "~foo()\n"); }
};

typedef boost::shared_ptr<foo> pFoo_t;

void doSomething( pFoo_t p)
{
    printf( "doing something...\n");
}

void doSomethingElse( pFoo_t p)
{
    printf( "doing something else...\n");
}

int main() {
    foo* pFoo = new foo;

    doSomething( pFoo_t( pFoo));
    doSomethingElse( pFoo_t( pFoo));

    return 0;
}
25
ответ дан Michael Burr 7 November 2019 в 11:28
поделиться

Если у Вас будет реестр общих объектов (список всех активных экземпляров, например), то объекты никогда не будут освобождаться. Решение: как в случае круговых структур зависимостей (см. ответ Дракона Kaz), используйте weak_ptr в качестве соответствующего.

-1
ответ дан Mr Fooz 7 November 2019 в 11:28
поделиться

Необходимо быть осторожными, когда Вы используете shared_ptr в коде мультипотока. Затем относительно легко стать в случай когда несколько shared_ptrs, указывая на ту же память, используется различными потоками.

1
ответ дан oo_olo_oo 7 November 2019 в 11:28
поделиться

При выделении shared_ptr <T> к этой внутренней части определение класса также опасно. Используйте enabled_shared_from_this вместо этого.

См. следующее сообщение здесь

1
ответ дан Community 7 November 2019 в 11:28
поделиться

Будьте тщательным созданием двух указателей на тот же объект.

boost::shared_ptr<Base> b( new Derived() );
{
  boost::shared_ptr<Derived> d( b.get() );
} // d goes out of scope here, deletes pointer

b->doSomething(); // crashes

вместо этого используйте это

boost::shared_ptr<Base> b( new Derived() );
{
  boost::shared_ptr<Derived> d = 
    boost::dynamic_pointer_cast<Derived,Base>( b );
} // d goes out of scope here, refcount--

b->doSomething(); // no crash

Кроме того, любые классы, содержащие shared_ptrs, должны определить конструкторов копии и операторы присваивания.

Не пытайтесь использовать shared_from_this () в конструкторе - он не будет работать. Вместо этого создайте статический метод создать класс и иметь его, возвращают shared_ptr.

Я передал ссылки на shared_ptrs без проблемы. Просто удостоверьтесь, что это копируется, прежде чем это сохранило (т.е. никакие ссылки как участники класса).

13
ответ дан 7 November 2019 в 11:28
поделиться

Построение анонимного временного общего указателя, например, в аргументах вызову функции:

f(shared_ptr<Foo>(new Foo()), g());

Это вызвано тем, что это допустимо для new Foo() выполняться, затем g() названный, и g() выдавать исключение, без shared_ptr когда-либо будучи настроенным, таким образом, shared_ptr не имеет шанса вымыться Foo объект.

18
ответ дан Brian Campbell 7 November 2019 в 11:28
поделиться

Не совсем ножное ружье, но определенно источник разочарования, пока вы не поймете, как это сделать способом C ++ 0x: большинство известных вам предикатов и любовь от плохо сочетается с shared_ptr . К счастью, std :: tr1 :: mem_fn работает с объектами, указателями и shared_ptr s, заменяя std :: mem_fun , но если вы хотите использовать ] std :: negate , std :: not1 , std :: plus или любой из тех старых друзей с shared_ptr , будьте готовы расслабиться с std :: tr1 :: bind и, возможно, заполнителями аргументов. На практике это гораздо более общий вариант, поскольку теперь вы в основном используете bind для каждого адаптера функционального объекта, но к этому нужно привыкнуть, если вы уже знакомы с удобными функциями STL.

Эта статья DDJ касается по теме с большим количеством примеров кода. Я также написал об этом несколько лет назад, когда мне впервые пришлось придумать, как это сделать.

4
ответ дан 7 November 2019 в 11:28
поделиться

Широко распространенное использование shared_ptr почти неизбежно приведет к нежелательному и невидимому использованию памяти.

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

Менее изучена проблема невыпущенных ссылок. Если объект совместно используется многими shared_ptr, он не будет уничтожен, пока каждый из них не будет обнулен или не выйдет за пределы области видимости. Очень легко упустить одну из этих ссылок и в конечном итоге получить невидимые в памяти объекты, которые, как вы думали, вы закончили.

Хотя, строго говоря, это не утечки памяти (все они будут выпущены до выхода из программы), они столь же опасны, и их труднее обнаружить.

Эти проблемы являются следствием целесообразных ложных деклараций: 1. Объявление того, что вы действительно хочу быть единоличным владельцем как shared_ptr. scoped_ptr будет правильным, но тогда любая другая ссылка на этот объект должна быть необработанным указателем, который можно оставить висящим. 2. Объявление того, что вы действительно хотите, чтобы пассивная ссылка наблюдения, как shared_ptr. weak_ptr будет правильным, но тогда у вас возникнут проблемы с преобразованием его в share_ptr каждый раз, когда вы захотите его использовать.

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

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

При единственном владении opObject = NULL; обязательно удалит объект и сделает это сейчас.

При совместном владении spObject = NULL; ........ кто знает? ......

0
ответ дан 7 November 2019 в 11:28
поделиться

Использование shared_ptr для очень маленьких объектов (например, char short ) может быть накладными расходами, если у вас много мелких объектов в куче, но на самом деле они не являются «общими». boost :: shared_ptr выделяет 16 байтов для каждого нового счетчика ссылок, который он создает в g ​​++ 4.4.3 и VS2008 с Boost 1.42. std :: tr1 :: shared_ptr выделяет 20 байт. Теперь, если у вас есть миллион различных shared_ptr , это означает, что 20 миллионов байтов вашей памяти потеряны при хранении только count = 1. Не говоря уже о косвенных расходах и фрагментации памяти. Попробуйте следующее на своей любимой платформе.

void * operator new (size_t size) {
  std::cout << "size = " << size << std::endl;
  void *ptr = malloc(size);
  if(!ptr) throw std::bad_alloc();
  return ptr;
}
void operator delete (void *p) {
  free(p);
}
3
ответ дан 7 November 2019 в 11:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: