Alokacja pamięci w funkcji a smart pointer

0

Cześć,
Czy w takiej sytuacji jak tu mam możliwość użycia jakiegoś smart pointera? Tworzę tutaj wskaźnik do obiektu pewnej klasy a potem jego adres wysyłam do funkcji w której tworzony jest dynamicznie obiekt a jego adres zapisywany jest do wskaźnika tak że mam go po wyjściu z tej funkcji.
Potem jest jakiś kod który operuje na tym wskaźniku i trzeba zwolnić pamięć. Tylko jak funkcja ma kilka ścieżek wyjścia to muszę w każdym miejscu zadbać o zwolnienie pamięci.

Problem w tym że ta funkcja getObject należy do zewnętrznej biblioteki dll i nie mogę zmienić jej interfejsu. Czyli nie mogę zmienić argumentu aby był to inny typ niż zwykły wskaźnik.
To co bym chyba chciał to to aby wraz z końcem życia zmiennej wskaźnikowej była też zwalniana pamięć na jaką wskazuje ten wskaźnik.

Przykładowy kod:

main()
{
myClass* myClasspointer = NULL;

getObject(&myClasspointer )

switch( condition)
{
case 1:
    myClasspointer ->fun1();
    if (myClasspointer);
       delete myClasspointer;
    return 1;
    
case 2:
    myClasspointer ->fun2()
    if (myClasspointer)
       delete myClasspointer;
    return 2;
case 3
    myClasspointer ->fun3()
    break;

    
default:
    break;
}

if (myClasspointer)
    delete myClasspointer;
return 0;

} 
4

Napisz sobie funkcję pomocniczą:

auto make_myClass()
{
	myClass* ret{};
	getObject(&ret);
	return std::unique_ptr<myClass>{ret};
}

Dalej nie powinno być problemów.

1

Konstruktor std::unique_ptr może przyjąć jakikolwiek wskaźnik. Możesz tutaj po prostu tego użyć.

Dodatkowo to co robisz nie ma sensu. Po co sprawdzać czy myClasspointer jest NULL skoro przed chwilą wywołałeś na nim metodę jakąś? Jeżeli już, to sprawdź to najpierw. Poza tym delete na wskaźniku NULL jest bezpieczne i nic nie robi.

0
#include <iostream>
using namespace std;

struct stupid
{
	stupid() { cout << "konstruktor\n"; }
	~stupid() { cout << "destruktor\n"; }
	void foo() { cout << "foo\n"; }
};

void nienaruszalna(stupid** s)
{
	*s = new stupid();
}

template <typename T>
struct my_smart_ptr
{
	T *value;
	T** operator &() { if (value) delete value; return &value; }	
	~my_smart_ptr() { if (value) delete value; }
	my_smart_ptr() : value(nullptr) {}
	T* operator ->() { return value; }
	my_smart_ptr(const my_smart_ptr&) = delete;
	my_smart_ptr& operator=(const my_smart_ptr&) = delete;
};

int main()
{
	my_smart_ptr<stupid> s;
	nienaruszalna(&s);
	s->foo();
}

Należy jednak pamiętać o tym, że ponowne użycie &s w jakimkolwiek kontekście zniszczy obiekt (wywoła destruktor).
Bez tego, ponowne wywołanie nienaruszalna(&s) spowodowałoby wyciek. Wóz albo przewóz...

0
Endrju napisał(a):

Konstruktor std::unique_ptr może przyjąć jakikolwiek wskaźnik. Możesz tutaj po prostu tego użyć.

Dodatkowo to co robisz nie ma sensu. Po co sprawdzać czy myClasspointer jest NULL skoro przed chwilą wywołałeś na nim metodę jakąś? Jeżeli już, to sprawdź to najpierw. Poza tym delete na wskaźniku NULL jest bezpieczne i nic nie robi.

Trochę kombinowałem próbując najpierw tworzyć tego unique pointera a potem go wysyłać do funkcji i się zastanawiałem jak tego potem użyć. W końcu wymyśliłem żeby go stworzyć jak już obiekt będzie gotowy. I teraz chciałbym się upewnić czy miałeś na myśli żeby zrobić to w taki sposób? Żeby go właśnie stworzyć jak już mam obiekt i żeby on sobie był tylko narzędziem które mi zniszczy obiekt gdy będzie niszczony unique pointer

 

main()
{
myClass* myClasspointer = NULL;

getObject(&myClasspointer )
unique_ptr<myClass> deleter(myClasspointer);

switch( condition)
{
case 1:
myClasspointer ->fun1();
return 1;

case 2:
myClasspointer ->fun2()
return 2;
case 3
myClasspointer ->fun3()
break;

default:
break;
}

return 0;

}

1

Przecież @kq już Ci pokazał jak masz to zrobić. To co on napisał zawiera to, co napisałem ja.

Chodzi o to, że powinieneś opakować ten wskaźnik w std::unique_ptr i zawsze już używać tego smart pointera w dalszym kodzie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1