Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Немножко про shared_ptr / 25 сообщений из 38, страница 1 из 2
18.12.2019, 10:06
    #39904507
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
Есть такой код:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
class A
{
// класс с shared_ptr внутри, и метод, возвращающий этот shared_ptr
public:
	A() { shpi_ = make_shared<int>(); }
	shared_ptr<int> GetPtr() { return shpi_; } // тут ни const, ни ссылки
private:
	shared_ptr<int> shpi_{nullptr};
};

void f()
{
// теперь пытаемся воспользоваться этим методом, разными способами.
	A a;
	shared_ptr<int>& shrpi = a.GetPtr(); // C2440, A non-const reference may only be bound to an lvalue
	shared_ptr<int> shpi = a.GetPtr(); // OK
	shared_ptr<int>&& shpcri = a.GetPtr(); // OK, but...
	*shpcri = 42;
}



Непонятно, почему нельзя заинтинить ссылку? Возвращается копия с shared_ptr же? Т.е. одно дело, если бы я возвращал временный объект. Или компилятор этого не знает и боится?

И мне до конца непонятен смысл константных ссылок, что происходит в третьей строке, и какие есть подводные камни и ограничения?
--------
Забегая немного назад, изначально вариант метода был такой:
Код: plaintext
1.
shared_ptr<int>& GetPtr() { return shpi_; }

но мне понадобилось иногда возвращать weak_ptr::lock(), а оно не хочет возвращать ссылку. Опять не совсем понятно, почему? lock возвращает shared_ptr.
Я немного пострадал по поводу оптимальности, убрал ссылку из возвращаемого результата, и тут выяснилось, что таким "указателем" нельзя инитить ссылки :(
...
Рейтинг: 0 / 0
18.12.2019, 12:22
    #39904621
petrav
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
CEMb
Непонятно, почему нельзя заинтинить ссылку? Возвращается копия с shared_ptr же? Т.е. одно дело, если бы я возвращал временный объект.

Твоя копия указателя - это тут и есть временный объект. Если ссылка будет не константной, то пропадут изменения в этом не константном временном объекте. Компилятор считает это не корректным.

Во второй строчке может сработать Return Value Optimization. И временного объекта не будет.

Про третью строчку, у меня есть обоснованное мнение, но я промолчу.

Вроде так. :)
...
Рейтинг: 0 / 0
18.12.2019, 12:27
    #39904630
petrav
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
CEMb
но мне понадобилось иногда возвращать weak_ptr::lock(), а оно не хочет возвращать ссылку. Опять не совсем понятно, почему? lock возвращает shared_ptr.

weak_ptr реализует слабую связь. Что бы с объектом, на который ссылается weak_ptr, можно было бы поработать - эту связь нужно временно превратить в сильную. Поэтому lock возвращает shared_ptr.

CEMb
Я немного пострадал по поводу оптимальности, убрал ссылку из возвращаемого результата, и тут выяснилось, что таким "указателем" нельзя инитить ссылки :(

Не очень понятно чего ты добиться хочешь.
...
Рейтинг: 0 / 0
18.12.2019, 19:01
    #39905022
petrav
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
CEMb

Забегая немного назад, изначально вариант метода был такой:
Код: plaintext
1.
shared_ptr<int>& GetPtr() { return shpi_; }

но мне понадобилось иногда возвращать weak_ptr::lock(), а оно не хочет возвращать ссылку. Опять не совсем понятно, почему? lock возвращает shared_ptr.

Небольшое дополнение. Если ты сделаешь как ты хочешь, а хочешь ты, видимо, так:

Код: plaintext
1.
shared_ptr<int>& GetPtr() { return veakPtrI_.lock(); }


То получится, что ты тут возвращаешь адрес (в виде ссылки) на временный объект, который лежит на стеке. И так тоже нельзя.
...
Рейтинг: 0 / 0
19.12.2019, 05:47
    #39905209
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
petrav
Твоя копия указателя - это тут и есть временный объект.
да, я что-то протормозил, думал о shared_ptr как о shared_ptr, "ну будет 2 указателя на объект, в результате...
petrav
Про третью строчку, у меня есть обоснованное мнение, но я промолчу.
Жаль, это было самое интересное, кроме того, что оно единственное работающее

petrav
То получится, что ты тут возвращаешь адрес (в виде ссылки) на временный объект, который лежит на стеке. И так тоже нельзя.
Ситуация была там такая:
- в объекте класса А есть 2 shared_ptr
- функция GetPtr в зависимости от условий возвращала один из них, как ссылку. Возвращать ссылку - это хорошо. Возвращать shared_ptr в моём случае - не очень хорошо, потому что ситуация "поработал и забыл", достаточно ссылки.
- условия для решения, что возвращать, передавались параметрами в GetPtr.
- потом обращение к объекту класса А стало итерационным, и по архитектурной задумке один из shared_ptr должен был стать текущим, его должен был возвращать GetPtr(без параметров) Т.е. кто-то внутри должен на него указывать(далее shared_ptr-ов может быть больше двух, они могут быть в векторе, перемешиваться, и так далее, поэтому просто индекс в качестве указующего не подойдёт).
- можно было бы взять ещё один shared_ptr и использовать его в качестве посредника, но, во-первых, как-то не совсем хорошо, во-вторых, может быть ситуация, когда текущий из shared_ptr-ов обнулился, а посредник будет держать объект живым, а вот weak_ptr может определить, что объекта уже нет (expired), но его lock - временный объект, вернуть ссылку на него нельзя.
ps: есть ещё вариант: возвращать просто указатель, потому что после GetPtr всё равно надо на null проверять.
...
Рейтинг: 0 / 0
19.12.2019, 09:54
    #39905257
petrav
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
CEMb
ps: есть ещё вариант: возвращать просто указатель, потому что после GetPtr всё равно надо на null проверять.

Смотри:

Код: plaintext
1.
2.
3.
4.
int *getPtr()
{
    return weakPtrI.lock().get();
}


На момент завершения работы этой функции локальный временный shared_ptr уже разрушен. Связь снова стала слабой. И когда ты воспользуешься возвращённым указателем -- объект из динамической памяти может быть уже удалён в другом потоке. И у тебя на руках сырой указатель в пустоту, и ты лезешь по нему.

Даже в однопоточном приложении можно получить такой эффект. Особенно в GUI приложении.
...
Рейтинг: 0 / 0
19.12.2019, 10:54
    #39905300
petrav
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
CEMb
- можно было бы взять ещё один shared_ptr и использовать его в качестве посредника, но, во-первых, как-то не совсем хорошо, во-вторых, может быть ситуация, когда текущий из shared_ptr-ов обнулился, а посредник будет держать объект живым, а вот weak_ptr может определить, что объекта уже нет (expired), но его lock - временный объект, вернуть ссылку на него нельзя.

Я так понял тебе weak_ptr<> вообще не нужен.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
class A
{
public:

    A()
    {
        arr.push_back(std::make_shared<int>(1));
        arr.push_back(std::make_shared<int>(2));
        arr.push_back(std::make_shared<int>(3));
        curr = 1;
    }

    std::shared_ptr<int> const &getPtr() const
    {
        return arr.at(curr);
    }

private:

    size_t curr = 0;
    std::vector<std::shared_ptr<int>> arr;
};

int main()
{
    A a;

    std::shared_ptr<int> const &p = a.getPtr();
    if (p != nullptr)
    {
        *p = 4;
    }
}
...
Рейтинг: 0 / 0
19.12.2019, 12:14
    #39905413
полудух
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
CEMb
ps: есть ещё вариант: возвращать просто указатель, потому что после GetPtr всё равно надо на null проверять.

если ptr требуется на null проверять, значит вы делаете что-то не то
а RAII тут точно нельзя применить?
RAII стоит впереди умных указателей
...
Рейтинг: 0 / 0
19.12.2019, 12:23
    #39905419
полудух
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
unique_ptr<widget> factory();
void caller()
{
    auto w = factory();
    auto g = make_unique<gadget>();
    use(*w, *g);
}
...
Рейтинг: 0 / 0
19.12.2019, 12:41
    #39905440
полудух
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
//##############################################################################
class Entity
{
  public:
    Entity(){
        cout << "created\n";
    }

    ~Entity(){
        cout << "destroyed\n";
    }
};

//##############################################################################
// тут ваще-т можно было бы прикрутить smart pointers
class ScopedPtr
{
    Entity* m_ptr;

  public:
    ScopedPtr(Entity* ptr) : m_ptr(ptr) {}

    ~ScopedPtr(){
        delete m_ptr;
    }
};

//##############################################################################
int main(int argc, char *argv[])
{
    system("clear");

    {
        ScopedPtr e = new Entity();
    }
}
...
Рейтинг: 0 / 0
19.12.2019, 13:19
    #39905504
petrav
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
полудух,

Хороши твои классы, прямо созданы для memory leak и падение приложения. А повторное использование прямо какое, а!
...
Рейтинг: 0 / 0
19.12.2019, 16:10
    #39905667
полудух
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
они не мои, а Страуструпа
и где у него leak?
...
Рейтинг: 0 / 0
19.12.2019, 16:10
    #39905668
полудух
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
второй Страуса, первый не помню
...
Рейтинг: 0 / 0
20.12.2019, 05:56
    #39905896
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
petrav
На момент завершения работы этой функции локальный временный shared_ptr уже разрушен. Связь снова стала слабой. И когда ты воспользуешься возвращённым указателем -- объект из динамической памяти может быть уже удалён в другом потоке. И у тебя на руках сырой указатель в пустоту, и ты лезешь по нему.
У меня там "короткая" функция, которая использует этот указатель. Но вообще, да, это я знаю, что у меня указатель будет использоваться очень быстро, а ни код, ни жизнь про это не знают: я потом забыл, написал код, который этот указатель куда-то передаёт или ещё что, и поехало. Поэтому, лучше возвращать копию shared_ptr, ну и, так-то, тема уже обсуждалась
petrav
curr = 1;
не нравится мне вариант с индексами: работаешь с массивом - надо следить за индексом. А weak_ptr сам это делает.

полудух
если ptr требуется на null проверять, значит вы делаете что-то не то
а RAII тут точно нельзя применить?
нет, всё хорошо, nullptr - это допустимое состояние объекта. Т.е. он может быть в рабочем и отключенном состоянии. Даже если RAII, всё равно придётся что-то проверять, перед тем, как с ним работать. В случае с RAII придётся ещё сам объект в каком-то виде держать в памяти.
-------
таким образом, получается, оптимальнее всего делать так:
1. weak_ptr внутри класса на один из shared_ptr
2. возвращаем shared_ptr, а не ссылку на него (но жаба душит всё ещё)
...
Рейтинг: 0 / 0
20.12.2019, 12:03
    #39906047
petrav
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
CEMb
таким образом, получается, оптимальнее всего делать так:
1. weak_ptr внутри класса на один из shared_ptr
2. возвращаем shared_ptr, а не ссылку на него (но жаба душит всё ещё)

Так заботишься о производительности что и объект не вернуть? :) Возможно там и не будет собственно возвращения временного объекта. Возможно сработает Return Value Optimization. Но там будет вещь на порядок хуже. Там будет атомарная инкрементация счётчика, с барьерами памяти и всем прочим.
...
Рейтинг: 0 / 0
20.12.2019, 18:16
    #39906314
petrav
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
полудух
они не мои, а Страуструпа
и где у него leak?

Во втором исходнике, который ты привёл, после операции копирования ScopedPtr будет сначала утечка памяти, а потом будет падение приложения.

Тот первый исходник, который ты привёл, тоже кривой. Из-за неоправданной операции разыменования интеллектуального указателя. Кроме того, концепция была не по делу применена.

ИМХО.
...
Рейтинг: 0 / 0
20.12.2019, 20:10
    #39906365
полудух
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
полудух
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
//##############################################################################
class Entity
{
  public:
    Entity(){
        cout << "created\n";
    }

    ~Entity(){
        cout << "destroyed\n";
    }
};

//##############################################################################
// тут ваще-т можно было бы прикрутить smart pointers
class ScopedPtr
{
    Entity* m_ptr;

  public:
    ScopedPtr(Entity* ptr) : m_ptr(ptr) {}

    ~ScopedPtr(){
        delete m_ptr;
    }
};

//##############################################################################
int main(int argc, char *argv[])
{
    system("clear");

    {
        ScopedPtr e = new Entity();
    }
}


petrav
полудух
они не мои, а Страуструпа
и где у него leak?

Во втором исходнике, который ты привёл, после операции копирования ScopedPtr будет сначала утечка памяти, а потом будет падение приложения.

copy, в смысле "ScopedPtr a = e;" ?
...
Рейтинг: 0 / 0
20.12.2019, 20:13
    #39906366
petrav
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
полудух

copy, в смысле "ScopedPtr a = e;" ?

Да.
...
Рейтинг: 0 / 0
20.12.2019, 20:20
    #39906367
полудух
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
а почему просто не создать новый ScopedPtr a = new Entity?

anyway, умные указатели там всё таки нужны, они тоже часть RAII.
...
Рейтинг: 0 / 0
20.12.2019, 20:29
    #39906371
petrav
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
полудух
а почему просто не создать новый ScopedPtr a = new Entity?

А если я хочу копию указателя на тот же объект? Может я случайно написал копирование. Не важно. Я не против разработки велосипедов, они помогают понять суть вещей. Но я против заведомого говнокода. В ваших примерах достаточно было заблокировать конструктор и оператор копирования. И всё было бы приемлимо.

полудух
anyway, умные указатели там всё таки нужны, они тоже часть RAII.

Твой ScopedPtr -- это и есть умный указатель и реализация RAII. Просто кривая реализация. И вредная для новичков, хотя и концептуально полезная. Но недостаточно.
...
Рейтинг: 0 / 0
20.12.2019, 21:32
    #39906392
полудух
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
я про это и говорю - пример у меня не полный (каюсь), в полном таки есть умные указатели.
petrav
В ваших примерах достаточно было заблокировать конструктор

зачем, там же make_shared?
...
Рейтинг: 0 / 0
21.12.2019, 02:39
    #39906431
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
petrav
Твой ScopedPtr -- это и есть умный указатель и реализация RAII. Просто кривая реализация. И вредная для новичков, хотя и концептуально полезная. Но недостаточно.

Для Полудуха: читайте про rule of three, ну и заодно про rule of five
https://en.wikipedia.org/wiki/Rule_of_three_(C _programming)
...
Рейтинг: 0 / 0
21.12.2019, 11:29
    #39906459
полудух
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
Anatoly Moskovsky, почитал, спасибо
...
Рейтинг: 0 / 0
22.12.2019, 00:11
    #39906601
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
CEMb,
Пишут же тебе всё человечьим голосом:

C2440, A non-const reference may only be bound to an lvalue
...
Рейтинг: 0 / 0
22.12.2019, 00:13
    #39906602
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Немножко про shared_ptr
Непонятно, почему нельзя заинтинить ссылку? Возвращается копия с shared_ptr же? Т.е. одно дело, если бы я возвращал временный объект.

Ты именно временный объект и возвращаешь.
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Немножко про shared_ptr / 25 сообщений из 38, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]