powered by simpleCommunicator - 2.0.58     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Немножко про shared_ptr
25 сообщений из 38, страница 1 из 2
Немножко про shared_ptr
    #39904507
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть такой код:
Код: 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
Немножко про shared_ptr
    #39904621
petrav
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb
Непонятно, почему нельзя заинтинить ссылку? Возвращается копия с shared_ptr же? Т.е. одно дело, если бы я возвращал временный объект.

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

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

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

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

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

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

Не очень понятно чего ты добиться хочешь.
...
Рейтинг: 0 / 0
Немножко про shared_ptr
    #39905022
petrav
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Немножко про shared_ptr
    #39905209
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Немножко про shared_ptr
    #39905257
petrav
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb
ps: есть ещё вариант: возвращать просто указатель, потому что после GetPtr всё равно надо на null проверять.

Смотри:

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


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

Даже в однопоточном приложении можно получить такой эффект. Особенно в GUI приложении.
...
Рейтинг: 0 / 0
Немножко про shared_ptr
    #39905300
petrav
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Немножко про shared_ptr
    #39905413
Фотография полудух
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb
ps: есть ещё вариант: возвращать просто указатель, потому что после GetPtr всё равно надо на null проверять.

если ptr требуется на null проверять, значит вы делаете что-то не то
а RAII тут точно нельзя применить?
RAII стоит впереди умных указателей
...
Рейтинг: 0 / 0
Немножко про shared_ptr
    #39905419
Фотография полудух
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: 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
Немножко про shared_ptr
    #39905440
Фотография полудух
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: 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
Немножко про shared_ptr
    #39905504
petrav
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
полудух,

Хороши твои классы, прямо созданы для memory leak и падение приложения. А повторное использование прямо какое, а!
...
Рейтинг: 0 / 0
Немножко про shared_ptr
    #39905667
Фотография полудух
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
они не мои, а Страуструпа
и где у него leak?
...
Рейтинг: 0 / 0
Немножко про shared_ptr
    #39905668
Фотография полудух
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
второй Страуса, первый не помню
...
Рейтинг: 0 / 0
Немножко про shared_ptr
    #39905896
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Немножко про shared_ptr
    #39906047
petrav
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb
таким образом, получается, оптимальнее всего делать так:
1. weak_ptr внутри класса на один из shared_ptr
2. возвращаем shared_ptr, а не ссылку на него (но жаба душит всё ещё)

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

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

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

ИМХО.
...
Рейтинг: 0 / 0
Немножко про shared_ptr
    #39906365
Фотография полудух
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
полудух
Код: 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
Немножко про shared_ptr
    #39906366
petrav
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
полудух

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

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

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

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

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

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

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

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

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

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


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