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?
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?
Jak go wprost usuniesz (delete
), to zostanie usunięty. Jak nie to dojdzie do wycieku pamięci.
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
).
Gdy wywołasz delete
na wskaźniku do niego. https://dsp.krzaq.cc/post/176/ucze-sie-cxx-kiedy-uzywac-new-i-delete/
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?
Właśnie dlatego nie powinieneś używać wskaźników praktycznie nigdy.
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?
Pod koniec funkcji możesz zwolnić wskaźnik i gitara.
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 ;)
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:
std::unique_ptr<QDoubleValidator> qvalidator{ new QDoubleValidator(0, 100, 2, this) };
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:
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>());
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.