семантика boost::shared_ptr (копирование)

Я просто хотел иметь свежую пару глаз, что приведенный ниже код верен в этом:

Указатели, содержащиеся в объекте trifoo (хранящемся в ptr_vector), являются общими указателями f, g, h.

Кроме того, каков результат копирования shared_ptr в конструкторе trifoo; это правильный метод «совместного использования» shared_ptr, обеспечивающий увеличение количества ссылок и т. д. Все мои другие сомнения, которые я смог проверить, чтобы проверить, но я не уверен, как я могу проверить это (правильно). Также приветствуется любая критика.

#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/shared_ptr.hpp>

class foo {
    int a, b;
public:
    foo(int A, int B) : a(A), b(B) {}
};

typedef boost::shared_ptr<foo> foo_ptr;

class trifoo {
    foo_ptr c, d, e;
public:
    trifoo(const foo_ptr& C, const foo_ptr& D, const foo_ptr& E) : c(C), d(D), e(E) {}
};

int main() {
    for (int i = 0; i < 5000000; i++) {
        foo_ptr f(new foo(1,2));
        foo_ptr g(new foo(2,3));
        foo_ptr h(new foo(4,5));

        boost::ptr_vector<trifoo> tris;

        tris.push_back(new trifoo(f, g, h));
    }

    return 0;
}

Примечание: бессмысленный цикл заключался в проверке утечек памяти, которых не было.


person deceleratedcaviar    schedule 30.01.2011    source источник
comment
Выглядит хорошо для меня. Однако вы должны предпочесть список инициализации присваиванию, и ваш вектор tris всегда будет иметь только один элемент, вы, вероятно, хотели, чтобы это было исключено из цикла.   -  person GManNickG    schedule 30.01.2011
comment
Это было просто для проверки возможностей ptr_vector, эта реализация не для практического применения - и спасибо.   -  person deceleratedcaviar    schedule 30.01.2011


Ответы (1)


Код кажется технически правильным.

Как бы то ни было, семантика копирования shared_ptr заключается в том, что счетчик ссылок на объект, на который делается ссылка, увеличивается. Это просто работает. Не о чем беспокоиться.

Однако некоторые проблемы со стилем:

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

  • Используйте списки инициализаторов конструктора вместо присваиваний, где это практически возможно.

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

Ура и чт.,

person Cheers and hth. - Alf    schedule 30.01.2011
comment
Спасибо за ответ, что касается фабричной функции, только что изучив эту концепцию, будет ли это (приблизительно) означать наличие такой функции, как: foo_ptr foo::makeFooPtr(int a, int b) { return foo_ptr(new foo (а, б)); } Или, по крайней мере, в том же духе. - person deceleratedcaviar; 30.01.2011
comment
Разве это не сохранит копию по ссылке (если копия будет сделана)? Я бы взял их по значению, а затем поменял бы на свои члены в C++03. - person GManNickG; 30.01.2011
comment
Это было моим самым большим сомнением, я не был уверен, как будет анализироваться shared_ptr, семантика того, что на самом деле копируется, была мне неясна. Я могу только представить, чтобы счетчик ссылок оставался согласованным, он должен указывать на один и тот же указатель независимо от копии? Кроме того, как я могу реализовать своп, как уже упоминалось. - person deceleratedcaviar; 30.01.2011
comment
@Daniel: см. вторую половину этот ответ. - person GManNickG; 30.01.2011
comment
Привет, Гман, интересные результаты нескольких тестов (простые тесты sys\time.h). Передача по значению, а затем c = C, была на 30% медленнее, чем: реализации c.swap(C) или const foo_ptr &C (которые были равны +-%5); и замедление заметно и при больших итерациях. Я решил использовать методы подкачки, но мне было интересно, можно ли сделать «c.swap(C)» в списке инициализаторов? Не то, чтобы это имело значение в любом случае. Обратите внимание, что все тесты проводились с небольшими итерациями около 500, потому что что-то было слишком большим, а результаты были слишком переменными (предположительно, из-за других процессов). - person deceleratedcaviar; 30.01.2011
comment
@Daniel: const-ref и copy-then-swap должны выполняться одинаково, за исключением случая, когда копия пропущена, что, возможно, не учитывалось в вашем тесте. (Хотя таймер может быть недостаточно точным, чтобы сказать об этом, а 500 итераций — это ужасно мало.) Это копирование и замена может быть выполнено в C++0x с семантикой перемещения (то есть вы перемещаете объекты, а не копируете их). , но пока нет. - person GManNickG; 31.01.2011
comment
Спасибо за подсказки, я не совсем уверен в истинном значении elision, но я читаю. Как я уже сказал, если я выполнял более 500 итераций, он становился слишком изменчивым между выполнениями, предположительно из-за других системных нагрузок. Меньшие итерации, но усредненные (то есть, может быть, 10 000 запусков, но никогда подряд) дали мне эти результаты. Ни одного теста из 500. - person deceleratedcaviar; 31.01.2011