operator new w argumencie funkcji

Odpowiedz Nowy wątek
2017-11-13 19:16
0

Przyjmijmy, że mam funkcję:

void f(const X *){}

i wywołuję gdzieś dalej:

f(new X())

Czy(ew. kiedy) obiekt stworzony przez new zostanie usunięty?

Pozostało 580 znaków

2017-11-13 19:17
1

Jak go wprost usuniesz (delete), to zostanie usunięty. Jak nie to dojdzie do wycieku pamięci.


Women were the reason I became a monk - and, ah, the reason I switched back...

Pozostało 580 znaków

2017-11-13 19:18
1

Nie. Musi zostać wywołany operator delete. Może być on wywołany niekoniecznie przez ciebie, ale przez np. smart pointer (np. std::unique_ptr).


Asm/C/C++

Pozostało 580 znaków

2017-11-13 19:18
kq
1

Gdy wywołasz delete na wskaźniku do niego. https://dsp.krzaq.cc/post/176[...]xx-kiedy-uzywac-new-i-delete/


Pozostało 580 znaków

2017-11-13 19:20
0

Ale gdzie i jak mam go usunąć? X wspomniany wcześniej to klasa, więc nie ma tu wskaźnika... Chyba, że w funkcji f jeśli nie będzie mi już potrzebny, tak?

edytowany 1x, ostatnio: fryderykst, 2017-11-13 19:21

Pozostało 580 znaków

2017-11-13 19:22
0

Właśnie dlatego nie powinieneś używać wskaźników praktycznie nigdy.

Pokaż pozostałe 2 komentarze
referencje, unique_ptr. Goły wskaźnik to praktycznie zawsze zły pomysł, a shared_ptr nie pamiętam kiedy faktycznie był niezbędny. - spartanPAGE 2017-11-13 21:09
@spartanPAGE: I tak się czasami robi w silnikach tylko musisz używać wszędobylskiego std::move w takim wypadku. Ale i też czasami używa się po prostu gołego wskaźnika, bywa różnie. A jak napisałem w przypadku klas qt to już raczej mało używalne. Pomijam już to że w kodzie korporacyjnym który jest olbrzymi zarzucone wszystko jest shared_ptr. - revcorey 2017-11-14 08:18
Ależ ja wiem. Nie mniej jednak jeżeli klepiesz kod "biznesowy" a nie super duper haksiorskie wydajne tricki, to powinieneś mieć odgórny zakaz używania gołych wskaźników. - spartanPAGE 2017-11-14 09:42
@spartanPAGE: i tu się zgodzę co więcej czasami nawet nie wskaźniki inteligętny a lepiej użyć referencje ale co poniektórym programistom c++ wydaje się że shared_ptr to taki GC. - revcorey 2017-11-14 09:46
imho shared_ptr powinno się używać wyłącznie wtedy, kiedy potrzebujesz funkcjonalności związanej z weak_ptr - spartanPAGE 2017-11-14 10:15

Pozostało 580 znaków

2017-11-13 19:28
0

Może wytłumaczę dokładniej, bo chciałem użyć unique_ptr właśnie, ale wtedy funkcja nie działała. Chodzi o Qt i sprawienie aby QLineEdit przyjmował tylko liczby rzeczywiste dodatnie. Znalazłem na SO:

ui.lineEdit_weight->setValidator(new QDoubleValidator(0, 100, 2, this));

To mi działa, chociaż można wpisać wartości większe niż 100... Ale, że naczytałem się na tym forum(szczególnie od @kq), żeby nie używać gołych wskaźników, to dałem coś takiego:

std::unique_ptr<QDoubleValidator> qvalidator{ new QDoubleValidator(0, 100, 2, this) };
ui.lineEdit_distance->setValidator(qvalidator.get());

To już mi nie działa...

Jak to zrobić poprawnie?

edytowany 2x, ostatnio: fryderykst, 2017-11-13 19:30
Przeczytaj czym jest unique_ptr. Po drugie używanie smartpointerów z klasami qt jest dość niepewne chociaż nie zawsze. Chodiz o zależność rodzic-dziecko. - revcorey 2017-11-13 19:41

Pozostało 580 znaków

2017-11-13 19:36
Mały Polityk
0

Pod koniec funkcji możesz zwolnić wskaźnik i gitara.

Pozostało 580 znaków

2017-11-13 19:52
0

Ok, udało mi się w "Kompendium wiedzy C++" znaleźć:

std::unique_ptr<QDoubleValidator> qvalidator{ new QDoubleValidator(0, 100, 2, this) };
ui.lineEdit_distance->setValidator(qvalidator.release());

Działa, ale w sumie nie wiem czemu dokładnie, więc jak można prosić o wytłumaczenie, będę wdzięczny ;)

edytowany 1x, ostatnio: fryderykst, 2017-11-13 19:52
Pokaż pozostałe 2 komentarze
bo nie znasz jeszcze qt ale za stackiem "The smart pointer classes std::unique_ptr and std::shared_ptr are for memory management. Having such a smart pointer means, that you own the pointer. However, when creating a QObject or a derived type with a QObject parent, the ownership (the responsibility to clean up) is handed over to the parent QObject. In that case, the standard library smart pointers are unnecessary, or even dangerous, since they can potentially cause a double deletion. Yikes!". Ogólnie nie używaj shared/qunique ptr z qt. - revcorey 2017-11-13 20:03
Czyli mam rozumieć, że funkcja setValidator() albo klasa QLineEdit sama się zajmie usunięciem wskaźnika, który przyjmuje jako argument? - fryderykst 2017-11-13 20:07
Jak podasz rodzica tym obiektom. Patrzyłeś w dokumentację qt? Nie bez parady w konstruktorze tam masz QObject * parent. https://stackoverflow.com/questions/34433435/why-dont-the-official-qt-examples-and-tutorials-use-smart-pointers - revcorey 2017-11-13 20:09
Czyli u mnie jak rodzicem jest this(QMainWindow), to wycieku nie ma, bo on się zajmie usunięciem wskaźnika, a ja się nie muszę tym martwić, dobrze rozumiem? - fryderykst 2017-11-13 21:12
jeśli obiekt rodzica będzie usuwany to i jego dzieci także. Zastanów się tylko ile dany obiekt może żyć itd. - revcorey 2017-11-14 08:19

Pozostało 580 znaków

2017-11-13 20:14
fryderykst napisał(a):
std::unique_ptr<QDoubleValidator> qvalidator{ new QDoubleValidator(0, 100, 2, this) };
ui.lineEdit_distance->setValidator(qvalidator.get());

To już mi nie działa...

Jak to zrobić poprawnie?

Najprościej - to tak:
1) w obiekcie ui poza funkcjami dodajesz to:

std::unique_ptr<QDoubleValidator> qvalidator{ new QDoubleValidator(0, 100, 2, this) };

2) tam gdzie ten kod miałeś:

ui.lineEdit_distance->setValidator(qvalidator.get());

Wyjaśnienie:
Zakładając że "ui" jest właścicielem kontrolki lineEdit_distance, qvalidator powinien istnieć tak długo jak ui, dlatego jeśli dodasz qvalidator jako pole w klasie, wszystko powinno być OK.
Aktualnie masz tak:

  • budujesz walidator
  • przypisujesz do kontrolki
  • usuwasz walidator z pamięci
  • kontrolka próbuje użyć walidatora
  • otrzymujesz efekt "nie działa"
edytowany 1x, ostatnio: vpiotr, 2017-11-13 20:16
Już się domyśliłem czytając to co podzrucił @revcorey i to co miałem w książce. Ale dzięki za wyjaśnienie, na pewno komuś się przyda :) - fryderykst 2017-11-13 20:18
Wg tego: http://doc.qt.io/qt-5/qtwidgets-widgets-lineedits-example.html to w ogóle nie musisz się przejmować smart pointerami w tym przypadku tylko normalnie użyć samego new, ale możesz to jeszcze gdzieś potwierdzić. Jeśli to prawda, to przy przekazywaniu wartości z unique_ptr lepiej użyć release(). - vpiotr 2017-11-13 20:20
No właśnie release() chyba przekazuje wartość, czyli kopiuje wskaźnik, bo z release() mi to działa, a get() nie, jeśli robię tak jak wyżej było. I ta pierwsza kwestia też mnie nurtuje cały czas. - fryderykst 2017-11-13 20:22
Tu masz jeszcze info które mówi że trzeba używać parenta żeby nie było wycieku: https://stackoverflow.com/questions/28099713/need-to-delete-qvalidator-manually - vpiotr 2017-11-13 20:23
release() powoduje, że unique_ptr nie będziesz próbował sprzątać po tym gołym wskaźniku gdy kończy swój żywot, a get() tego nie daje. W momencie gdy obiekt Qt już zajmuje się sprzątaniem, ponowne sprzątanie przez unique_ptr jest niepożądane. - twonek 2017-11-13 21:28

Pozostało 580 znaków

2017-11-14 15:12
1

stare C++ bez wycieku:

void f(const X *){}
 
X x;
f(&x);

C++14

void f(const X *){}
 
f(std::make_unique<X>().get());

albo

void f(std::unique_ptr<X>&&){}
 
f(std::make_unique<X>());

W Qt masz masz zarządzanie pamięcią za pomocą drzewa i relacji rodzic dziecko, przykładowo to:

new QDoubleValidator(0, 100, 2, this)

Tworzy obiekt QDoubleValidator którego właścicielem (rodzicem) jest obiekt wskazywany przez this (przypuszczalnie MainWindow).
W tym wypadku jak tylko MainWindow zostanie usuniete to wraz z nim QDoubleValidator pójdzie do piachu.

Wcześniejsza odpowiedź w której mieszany jest mechanizm rodzić-dziecko z Qt z std::unique_ptr<QDoubleValidator>, grozi crashem jeśli rodzic zginie przed std::unique_ptr<QDoubleValidator> (wtedy unique_ptr będzie wskazywał na martwy obiekt).
Sprzątanie w odwrotnej kolejności nie kończy się crashem bo usunięcie QObject (za pomocą unique_ptr) automatycznie usuwa go z drzewa - rodzić jest notyfikowany o śmierci dziecka i usuwany z listy obiektów do usunięcia.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 3x, ostatnio: MarekR22, 2017-11-14 15:22
Panie, tutaj masz nie tyle wyciek co UB f(std::make_unique<X>().get());. EDIT, Czy UB to nie jestem pewien, zależy co f() będzie robić ze wskaźnikiem (tu nie robi nic) - stryku 2017-11-14 15:27
To nie jest UB: przykład, cppreference: "All temporary objects are destroyed as the last step in evaluating the full-expression that (lexically) contains the point where they were created, and if multiple temporary objects were created, they are destroyed in the order opposite to the order of creation." StackOverflow. - MarekR22 2017-11-15 15:29
No to się czegoś nauczyłem. Parę lat temu dałbym sobie rękę uciąć. I bym teraz nie miał ręki. Dzięki! (: - stryku 2017-11-15 16:39

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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