Rawtherapee: Crash in newlocallab

Created on 3 Apr 2019  ·  45Comments  ·  Source: Beep6581/RawTherapee

After working on an image in newlocallab, I often get a crash. Using a debug build, I don't get anything from gdb (bt full returns "no stack").
It seems to happen either when working on a spot, or even sometimes just when exporting in jpeg.
What I observed, though, is that memory usage seems to increase a lot, and during the last crash RT was using over 5 GB of RAM.
In my latest test, I had an image with 11 RTspots, and I started duplicating a spot (5 copies). With each copy, the RAM usage was going up a bit, but strangely memory usage kept going up as I deleted those copied spots.
I guess the crashes I observed were due to memory saturation (leak)?

Edit: for information, the crashes and test were made on a 24 MP image. When I first open the same image with 12 active RTspots, RT occupies less than 900MB.

local adjustments bug

All 45 comments

Additional info (using a debug build):
Each time I export the image, the memory goes up, and after the export the state of memory usage doesn't go all the way down to the initial state.
Example:
1) open a 24MP file -> _900MB_
2) turn some filters on, create RTspots, play with them (create, duplicate, delete, add...) -> _1.84GB_
3) export # 1 -> memory peak at _3.87GB_ -> _2.05GB_ when exporting is done
4) export # 2 (nothing changed in between) -> peak at _3.44GB_ -> _2.17GB_ when done
5) export # 3 -> peak at _3.58GB_ -> _2.35_ when done

By just clicking 3 times on the the save button, without touching anything to the image, memory usage goes from _1.84_ to _2.35GB_.

Update: it looks like it's at least in the CbDL filter, but not in Exposure. I'll post the results of a test in about 1 hour.

Here's a result, using a release build from the official locallab. I saved a 24MP image 9 times in a row, without changing anything in RT, and wrote down the memory usage of RT after each export.

Here, I report the average change in memory usage between 2 consecutive exports:

  • Local Lab OFF: ~0.007 GB
  • Local Lab ON, zero spot added: ~0.006 GB
  • Local Lab ON, 10 spots added, no filter: ~0.007 GB
  • Local Lab ON, 10 spots added, exposure compensation: ~0.016 GB
  • Local Lab ON, 10 spots added, CbDL: ~0.127 GB

I think the increased memory usage by CbDL is the cause of the crashes I've seen, at some point during export RT need more memory than available (I have only 8GB of RAM on my machine).

@Desmis I tried the same procedure as above (saving 9 times and recording the change in memory usage) using 10 31x31 RTspots with CbDL, now the increase in memory is much less (~0.023 GB).

I find CbDL in local lab to be very useful as a skin retouch tool, so I tend to use between 5 and 10 CbDL RTspots of varying size, and I generally export several times to see the effect in the resized final image, which is why my RAM usage ends up full and makes RT crash.

@sguyader
I test with Colorspace_flower.pef
I create, duplicate 10 spots, all with CBDL
50% small, 50% big all with very high or vey low values "contrast"

I save to "Photoshop" 8 times

Memory at the bebining = 460
Memory at the end = 465
Pic when saving = 950

I found a bug in CBDL see #5247
But it's not memory, but allocaction for wavelet decomposition
I think in most cases it's solved.... to verify

jacques

@sguyader
have you tried with last commit ?
My solution to prevent crash is not optimized, but do you need spot smaller than 32*32, it's very small ?

2x2 ==> 1 level decomposition
4x4 ==> 2
8x8 ==> 3
16x16 ==> 4
32x32 ==> 5 levels decompostion
you can use low transition with high tansition weakening

@Desmis I didn't read correctly what you said regarding the 32x32 size, I thought you meant the problem was only when the size of the are is less than 32x32, so I tried 31x31. But it was with an older commit.
I'll try the new commit later, maybe tomorrow.

@sguyader
In some cases - rare - when spots is limited to 32x32 I have a crash (very rare), I think due to round float to integer...
Whithout the last commit, with very small spots, in all cases crash (when zoom; when save...)
With last commit in 99% cases, no crash

I don't know... before last commit, I tried 10 spots at 31x31 and I had no crash in 9 saves (but I didn't zoom or change anything else).

@sguyader @Desmis The crashes are caused by my optimizations. Before my optimizations the area cbdl was working on, always was quite large. With optimizations the area could be really small (even less than 32x32 px) and I didn't see that's a problem for cbdl algorithm.

Mea culpa, but I think it's for the good. We likely will find some more bugs by my optimizations.

@Desmis @heckflosse
I don't know what to say. I compiled the latest commit to newlocallab, and did the same test as yesterday : open an image, add 1 RTspot with CbDL active and duplicated it to get 10 spots in total, and saved 9 times. Memory didn't jump as much as yesterday, it went from 1.33 to 1.54GB for 9 saves (~210MB increase). But then I kept playing on the image, only switching several times from fit image to whole screen to 1:1 preview, back and forth, saving a couple times, going back in history to the first spot add, saving again a couple times... Now memory usage is 2.35GB with only 1 RTspot active. So it's 1GB used since I first added the spots.
Is it something that can be expected? Because I'm afraid that if I'd be working longer on the image, I could again hit the maximum of memory available and get crash.

@sguyader Sounds like a memory leak. Are you using only cbdl in locallab?

@heckflosse yes I was using only CbDL. But now I did another experiment, with the same image but using the neutral profile, after just saving 20 times memory usage went from 2.05GB to 2.15GB. Not a lot, but the trend is still there and I don't understand why it would occur as there's no filter active. I was starting to wonder if it could be a problem in the xtrans demosaicing or some other early step, but I just did 20 saves but this time by directly sending the image to the queue from the file browser, and there was no additional memory used.

@sguyader Can you reproduce also on dev (using neutral profile)?

In dev (Version: 5.5-154-gdb57a023), METOW mode:

  • just opening the image with neutral profile -> 777MB
  • switching back and forth between fit to screen and 1:1, back to fit to screen -> 820MB
  • saving 20 times using the "Save" button -> 948MB (sometimes went up to 998MB)
  • saving 20 times from queue, image open in editor: goes from 808MB -> 852MB -> after 20 more saves 896MB
  • saving 20 times from queue, no image in editor: goes from 412MB -> 413MB

@sguyader Ok, seems unrelated to newlocallab then.

@heckflosse indeed I guess it was emphasized at some point by CbDL in locallab.
Should I close this issue?

@sguyader Let's wait. As there seems to be a memory leak somewhere, maybe @Floessie wants to chime in. Then we can create a new issue or change the title of this one

Another test with the locallab build:

  1. open image in editor (own window) with 12 RTspots (10 CbDL, 2 Color & Light) from a previous profile: 895 MB
  2. then selecting each spot from the list (to check their filters) + zooming in/out 5 times -> 1.40 GB
  3. then 20 saves through save button -> 2.45 GB
  4. then 20 saves from queue -> 2.50 GB
  5. then 20 additional saves from save button -> 2.94 GB

The memory leak (if there is) seems to occur mainly when saving from the editor (also seen in SETM mode in dev build), but not from the queue.

@heckflosse @Floessie wouldn't it help if @sguyader compiled a debug build and ran it through valgrind --leak-check? If so, what are your recommended settings?

@Beep6581 Valgrind is awfully slow. I'm currently running a -DWITH_SAN=address debug build. It already found two rather obvious leaks here. Maybe they fragment the memory for @sguyader?

For glibc this should always be taken into account when hunting RSS leaks, IMHO.

Best,
Flössie

Same kind of leak in here.

@Desmis @Pandagrapher I don't see a reason why defSpot and friends should be on the heap...

Next one here.

Preparing a patch...

@Floessie
OK, thank you :)
jacques

It has gotten bigger than I first expected. There are still other leaks I omitted to fix. The most prominent is in ControlSpotPanel::addControlSpotCurve() which might already be fixed in another branch (I remember discussing it with @Hombre57).

There are DOS line endings in some files on this branch.

Here's the patch:

diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc
index 2064a89a6..3c6345c50 100644
--- a/rtengine/procparams.cc
+++ b/rtengine/procparams.cc
@@ -4912,7 +4912,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
             // Initialize LocallabSpotEdited to false according to nbspot
             if (pedited) {
                 pedited->locallab.spots.clear();
-                pedited->locallab.spots.resize(locallab.nbspot, new LocallabParamsEdited::LocallabSpotEdited(false));
+                pedited->locallab.spots.resize(locallab.nbspot, LocallabParamsEdited::LocallabSpotEdited(false));
             }

             for (int i = 0; i < locallab.nbspot; i++) {
diff --git a/rtgui/controlspotpanel.cc b/rtgui/controlspotpanel.cc
index 0fecf9b54..24023abed 100644
--- a/rtgui/controlspotpanel.cc
+++ b/rtgui/controlspotpanel.cc
@@ -1662,18 +1662,18 @@ ControlSpotPanel::SpotRow* ControlSpotPanel::getSpot(int id)
     return nullptr;
 }

-std::vector<int>* ControlSpotPanel::getSpotIdList()
+std::vector<int> ControlSpotPanel::getSpotIdList()
 {
     MyMutex::MyLock lock(mTreeview);

-    std::vector<int>* r = new std::vector<int>();
+    std::vector<int> r;

     Gtk::TreeModel::Children children = treemodel_->children();
     Gtk::TreeModel::Children::iterator iter;

     for (iter = children.begin(); iter != children.end(); iter++) {
         Gtk::TreeModel::Row row = *iter;
-        r->push_back(row[spots_.id]);
+        r.push_back(row[spots_.id]);
     }

     return r;
@@ -1918,7 +1918,7 @@ ControlSpotPanel::SpotEdited* ControlSpotPanel::getEditedStates()
     return se;
 }

-void ControlSpotPanel::setEditedStates(SpotEdited* se)
+void ControlSpotPanel::setEditedStates(const SpotEdited& se)
 {
     // printf("setEditedStates\n");

@@ -1932,7 +1932,7 @@ void ControlSpotPanel::setEditedStates(SpotEdited* se)
     disableParamlistener(true);

     // Set widgets edited states
-    if (!se->nbspot || !se->selspot) {
+    if (!se.nbspot || !se.selspot) {
         treeview_.set_sensitive(false);
         button_add_.set_sensitive(false);
         button_delete_.set_sensitive(false);
@@ -1944,44 +1944,44 @@ void ControlSpotPanel::setEditedStates(SpotEdited* se)
         button_add_.set_sensitive(true);
         button_delete_.set_sensitive(true);
         button_duplicate_.set_sensitive(true);
-        button_rename_.set_sensitive(se->name);
-        button_visibility_.set_sensitive(se->isvisible);
+        button_rename_.set_sensitive(se.name);
+        button_visibility_.set_sensitive(se.isvisible);
     }

-    if (!se->shape) {
+    if (!se.shape) {
         shape_->set_active_text(M("GENERAL_UNCHANGED"));
     }

-    if (!se->spotMethod) {
+    if (!se.spotMethod) {
         spotMethod_->set_active_text(M("GENERAL_UNCHANGED"));
     }

-    sensiexclu_->setEditedState(se->sensiexclu ? Edited : UnEdited);
-    structexclu_->setEditedState(se->structexclu ? Edited : UnEdited);
-    struc_->setEditedState(se->struc ? Edited : UnEdited);
+    sensiexclu_->setEditedState(se.sensiexclu ? Edited : UnEdited);
+    structexclu_->setEditedState(se.structexclu ? Edited : UnEdited);
+    struc_->setEditedState(se.struc ? Edited : UnEdited);

-    if (!se->shapeMethod) {
+    if (!se.shapeMethod) {
         shapeMethod_->set_active_text(M("GENERAL_UNCHANGED"));
     }

-    locX_->setEditedState(se->locX ? Edited : UnEdited);
-    locXL_->setEditedState(se->locXL ? Edited : UnEdited);
-    locY_->setEditedState(se->locY ? Edited : UnEdited);
-    locYT_->setEditedState(se->locYT ? Edited : UnEdited);
-    centerX_->setEditedState(se->centerX ? Edited : UnEdited);
-    centerY_->setEditedState(se->centerY ? Edited : UnEdited);
-    circrad_->setEditedState(se->circrad ? Edited : UnEdited);
+    locX_->setEditedState(se.locX ? Edited : UnEdited);
+    locXL_->setEditedState(se.locXL ? Edited : UnEdited);
+    locY_->setEditedState(se.locY ? Edited : UnEdited);
+    locYT_->setEditedState(se.locYT ? Edited : UnEdited);
+    centerX_->setEditedState(se.centerX ? Edited : UnEdited);
+    centerY_->setEditedState(se.centerY ? Edited : UnEdited);
+    circrad_->setEditedState(se.circrad ? Edited : UnEdited);

-    if (!se->qualityMethod) {
+    if (!se.qualityMethod) {
         qualityMethod_->set_active_text(M("GENERAL_UNCHANGED"));
     }

-    transit_->setEditedState(se->transit ? Edited : UnEdited);
-    thresh_->setEditedState(se->thresh ? Edited : UnEdited);
-    iter_->setEditedState(se->iter ? Edited : UnEdited);
-    balan_->setEditedState(se->balan ? Edited : UnEdited);
-    transitweak_->setEditedState(se->transitweak ? Edited : UnEdited);
-    avoid_->set_inconsistent(multiImage && !se->avoid);
+    transit_->setEditedState(se.transit ? Edited : UnEdited);
+    thresh_->setEditedState(se.thresh ? Edited : UnEdited);
+    iter_->setEditedState(se.iter ? Edited : UnEdited);
+    balan_->setEditedState(se.balan ? Edited : UnEdited);
+    transitweak_->setEditedState(se.transitweak ? Edited : UnEdited);
+    avoid_->set_inconsistent(multiImage && !se.avoid);

     // Update Control Spot GUI according to widgets edited states
     updateParamVisibility();
@@ -2004,27 +2004,27 @@ void ControlSpotPanel::setDefaults(const rtengine::procparams::ProcParams * defP
     }

     // Set default values for adjusters
-    const rtengine::procparams::LocallabParams::LocallabSpot* defSpot = new rtengine::procparams::LocallabParams::LocallabSpot();
+    rtengine::procparams::LocallabParams::LocallabSpot defSpot;

     if (index != -1 && index < (int)defParams->locallab.spots.size()) {
-        defSpot = &defParams->locallab.spots.at(index);
-    }
-
-    sensiexclu_->setDefault((double)defSpot->sensiexclu);
-    structexclu_->setDefault((double)defSpot->structexclu);
-    struc_->setDefault(defSpot->struc);
-    locX_->setDefault((double)defSpot->locX);
-    locXL_->setDefault((double)defSpot->locXL);
-    locY_->setDefault((double)defSpot->locY);
-    locYT_->setDefault((double)defSpot->locYT);
-    centerX_->setDefault((double)defSpot->centerX);
-    centerY_->setDefault((double)defSpot->centerY);
-    circrad_->setDefault((double)defSpot->circrad);
-    transit_->setDefault((double)defSpot->transit);
-    thresh_->setDefault(defSpot->thresh);
-    iter_->setDefault(defSpot->iter);
-    balan_->setDefault(defSpot->balan);
-    transitweak_->setDefault(defSpot->transitweak);
+        defSpot = defParams->locallab.spots.at(index);
+    }
+
+    sensiexclu_->setDefault((double)defSpot.sensiexclu);
+    structexclu_->setDefault((double)defSpot.structexclu);
+    struc_->setDefault(defSpot.struc);
+    locX_->setDefault((double)defSpot.locX);
+    locXL_->setDefault((double)defSpot.locXL);
+    locY_->setDefault((double)defSpot.locY);
+    locYT_->setDefault((double)defSpot.locYT);
+    centerX_->setDefault((double)defSpot.centerX);
+    centerY_->setDefault((double)defSpot.centerY);
+    circrad_->setDefault((double)defSpot.circrad);
+    transit_->setDefault((double)defSpot.transit);
+    thresh_->setDefault(defSpot.thresh);
+    iter_->setDefault(defSpot.iter);
+    balan_->setDefault(defSpot.balan);
+    transitweak_->setDefault(defSpot.transitweak);

     // Set default edited states for adjusters
     if (!pedited) {
@@ -2044,27 +2044,27 @@ void ControlSpotPanel::setDefaults(const rtengine::procparams::ProcParams * defP
         balan_->setDefaultEditedState(Irrelevant);
         transitweak_->setDefaultEditedState(Irrelevant);
     } else {
-        const LocallabParamsEdited::LocallabSpotEdited* defSpotState = new LocallabParamsEdited::LocallabSpotEdited(true);
+        LocallabParamsEdited::LocallabSpotEdited defSpotState(true);

         if (index != 1 && index < (int)pedited->locallab.spots.size()) {
-            defSpotState = &pedited->locallab.spots.at(index);
+            defSpotState = pedited->locallab.spots.at(index);
         }

-        sensiexclu_->setDefaultEditedState(defSpotState->sensiexclu ? Edited : UnEdited);
-        structexclu_->setDefaultEditedState(defSpotState->structexclu ? Edited : UnEdited);
-        struc_->setDefaultEditedState(defSpotState->struc ? Edited : UnEdited);
-        locX_->setDefaultEditedState(defSpotState->locX ? Edited : UnEdited);
-        locXL_->setDefaultEditedState(defSpotState->locXL ? Edited : UnEdited);
-        locY_->setDefaultEditedState(defSpotState->locY ? Edited : UnEdited);
-        locYT_->setDefaultEditedState(defSpotState->locYT ? Edited : UnEdited);
-        centerX_->setDefaultEditedState(defSpotState->centerX ? Edited : UnEdited);
-        centerY_->setDefaultEditedState(defSpotState->centerY ? Edited : UnEdited);
-        circrad_->setDefaultEditedState(defSpotState->circrad ? Edited : UnEdited);
-        transit_->setDefaultEditedState(defSpotState->transit ? Edited : UnEdited);
-        thresh_->setDefaultEditedState(defSpotState->thresh ? Edited : UnEdited);
-        iter_->setDefaultEditedState(defSpotState->iter ? Edited : UnEdited);
-        balan_->setDefaultEditedState(defSpotState->balan ? Edited : UnEdited);
-        transitweak_->setDefaultEditedState(defSpotState->transitweak ? Edited : UnEdited);
+        sensiexclu_->setDefaultEditedState(defSpotState.sensiexclu ? Edited : UnEdited);
+        structexclu_->setDefaultEditedState(defSpotState.structexclu ? Edited : UnEdited);
+        struc_->setDefaultEditedState(defSpotState.struc ? Edited : UnEdited);
+        locX_->setDefaultEditedState(defSpotState.locX ? Edited : UnEdited);
+        locXL_->setDefaultEditedState(defSpotState.locXL ? Edited : UnEdited);
+        locY_->setDefaultEditedState(defSpotState.locY ? Edited : UnEdited);
+        locYT_->setDefaultEditedState(defSpotState.locYT ? Edited : UnEdited);
+        centerX_->setDefaultEditedState(defSpotState.centerX ? Edited : UnEdited);
+        centerY_->setDefaultEditedState(defSpotState.centerY ? Edited : UnEdited);
+        circrad_->setDefaultEditedState(defSpotState.circrad ? Edited : UnEdited);
+        transit_->setDefaultEditedState(defSpotState.transit ? Edited : UnEdited);
+        thresh_->setDefaultEditedState(defSpotState.thresh ? Edited : UnEdited);
+        iter_->setDefaultEditedState(defSpotState.iter ? Edited : UnEdited);
+        balan_->setDefaultEditedState(defSpotState.balan ? Edited : UnEdited);
+        transitweak_->setDefaultEditedState(defSpotState.transitweak ? Edited : UnEdited);
     }
 }

diff --git a/rtgui/controlspotpanel.h b/rtgui/controlspotpanel.h
index 45afdb23d..7352e75ca 100644
--- a/rtgui/controlspotpanel.h
+++ b/rtgui/controlspotpanel.h
@@ -21,6 +21,8 @@
 #ifndef _CONTROLSPOTPANEL_H_
 #define _CONTROLSPOTPANEL_H_

+#include <memory>
+
 #include "../rtengine/coord.h"
 #include "adjuster.h"
 #include "editcallbacks.h"
@@ -126,7 +128,7 @@ public:
      *
      * @return A vector contening the list of spot id
      */
-    std::vector<int>* getSpotIdList();
+    std::vector<int> getSpotIdList();
     /**
      * Getter of selected spot id
      *
@@ -182,7 +184,7 @@ public:
      *
      * @param se A SpotEdited structure containing the widgets edited states to update
      */
-    void setEditedStates(SpotEdited* se);
+    void setEditedStates(const SpotEdited& se);
     /**
      * Implementation of setDefaults function of toolpanel.h
      *
@@ -351,7 +353,7 @@ private:

     // Internal variables
     int lastObject_;
-    rtengine::Coord* lastCoord_;
+    std::unique_ptr<rtengine::Coord> lastCoord_;
     bool nbSpotChanged_;
     bool selSpotChanged_;
     bool nameChanged_;
diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc
index 6e101a7cf..76dae98a2 100644
--- a/rtgui/editorpanel.cc
+++ b/rtgui/editorpanel.cc
@@ -1748,7 +1748,7 @@ void EditorPanel::procParamsChanged (Thumbnail* thm, int whoChangedIt)
         PartialProfile pp (true);
         pp.set (true);
         * (pp.pparams) = openThm->getProcParams();
-        pp.pedited->locallab.spots.resize(pp.pparams->locallab.nbspot, new LocallabParamsEdited::LocallabSpotEdited(true));
+        pp.pedited->locallab.spots.resize(pp.pparams->locallab.nbspot, LocallabParamsEdited::LocallabSpotEdited(true));
         tpc->profileChange (&pp, rtengine::EvProfileChangeNotification, M ("PROGRESSDLG_PROFILECHANGEDINBROWSER"));
         pp.deleteInstance();
     }
diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc
index a91fa209d..61bfc62c4 100644
--- a/rtgui/filebrowser.cc
+++ b/rtgui/filebrowser.cc
@@ -1404,7 +1404,7 @@ void FileBrowser::applyPartialMenuItemActivated (ProfileStoreLabel *label)
                 rtengine::procparams::PartialProfile dstProfile(true);
                 *dstProfile.pparams = (static_cast<FileBrowserEntry*>(selected[i]))->thumbnail->getProcParams ();
                 dstProfile.set(true);
-                dstProfile.pedited->locallab.spots.resize(dstProfile.pparams->locallab.nbspot, new LocallabParamsEdited::LocallabSpotEdited(true));
+                dstProfile.pedited->locallab.spots.resize(dstProfile.pparams->locallab.nbspot, LocallabParamsEdited::LocallabSpotEdited(true));
                 partialPasteDlg.applyPaste (dstProfile.pparams, dstProfile.pedited, srcProfiles->pparams, srcProfiles->pedited);
                 (static_cast<FileBrowserEntry*>(selected[i]))->thumbnail->setProcParams (*dstProfile.pparams, dstProfile.pedited, FILEBROWSER);
                 dstProfile.deleteInstance();
diff --git a/rtgui/history.cc b/rtgui/history.cc
index b116b0cdc..bc3e2164c 100644
--- a/rtgui/history.cc
+++ b/rtgui/history.cc
@@ -179,7 +179,7 @@ void History::historySelectionChanged ()
         if (row && tpc) {
             ProcParams pparams = row[historyColumns.params];
             ParamsEdited pe (true);
-            pe.locallab.spots.resize(pparams.locallab.nbspot, new LocallabParamsEdited::LocallabSpotEdited(true));
+            pe.locallab.spots.resize(pparams.locallab.nbspot, LocallabParamsEdited::LocallabSpotEdited(true));
             PartialProfile pp (&pparams, &pe);
             ParamsEdited paramsEdited = row[historyColumns.paramsEdited];

@@ -214,7 +214,7 @@ void History::bookmarkSelectionChanged ()
         if (row && tpc) {
             ProcParams pparams = row[bookmarkColumns.params];
             ParamsEdited pe (true);
-            pe.locallab.spots.resize(pparams.locallab.nbspot, new LocallabParamsEdited::LocallabSpotEdited(true));
+            pe.locallab.spots.resize(pparams.locallab.nbspot, LocallabParamsEdited::LocallabSpotEdited(true));
             PartialProfile pp (&pparams, &pe);
             ParamsEdited paramsEdited = row[bookmarkColumns.paramsEdited];
             tpc->profileChange (&pp, EvBookmarkSelected, row[bookmarkColumns.text], &paramsEdited);
diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc
index 1a3a2116a..eacd225a7 100644
--- a/rtgui/locallab.cc
+++ b/rtgui/locallab.cc
@@ -228,8 +228,7 @@ Locallab::Locallab():

     // Others
     defparams(nullptr),
-    defpedited(nullptr),
-    pe(nullptr)
+    defpedited(nullptr)
 {
     ToolVBox* const panel = Gtk::manage(new ToolVBox());

@@ -1245,10 +1244,8 @@ void Locallab::read(const ProcParams* pp, const ParamsEdited* pedited)
     }

     // Delete all existent spots
-    std::vector<int>* const list = expsettings->getSpotIdList();
-
-    for (size_t i = 0; i < list->size(); i++) {
-        expsettings->deleteControlSpot(list->at(i));
+    for (auto id : expsettings->getSpotIdList()) {
+        expsettings->deleteControlSpot(id);
     }

     // Add existent spots based on pp
@@ -1349,70 +1346,69 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited)
     const int spotPanelEvent = expsettings->getEventType();
     int spotId;
     ControlSpotPanel::SpotRow* r;
-    LocallabParams::LocallabSpot* newSpot;
+    LocallabParams::LocallabSpot newSpot;

-    switch (spotPanelEvent) {
+    switch (spotPanelEvent) { // TODO: This needs to be cleaned up with `case` scopes and a proper `enum class`
         case (1): // 1 = Spot creation event
             // Spot creation (default initialization)
-            newSpot = new LocallabParams::LocallabSpot();
             spotId = expsettings->getNewId();
             r = new ControlSpotPanel::SpotRow();
-            r->id = newSpot->id = spotId;
-            r->name = newSpot->name = M("TP_LOCALLAB_SPOTNAME") + std::to_string(spotId);
-            r->isvisible = newSpot->isvisible;
+            r->id = newSpot.id = spotId;
+            r->name = newSpot.name = M("TP_LOCALLAB_SPOTNAME") + std::to_string(spotId);
+            r->isvisible = newSpot.isvisible;

-            if (newSpot->shape == "ELI") {
+            if (newSpot.shape == "ELI") {
                 r->shape = 0;
             } else {
                 r->shape = 1;
             }

-            if (newSpot->spotMethod == "norm") {
+            if (newSpot.spotMethod == "norm") {
                 r->spotMethod = 0;
             } else {
                 r->spotMethod = 1;
             }

-            r->sensiexclu = newSpot->sensiexclu;
-            r->structexclu = newSpot->structexclu;
-            r->struc = newSpot->struc;
+            r->sensiexclu = newSpot.sensiexclu;
+            r->structexclu = newSpot.structexclu;
+            r->struc = newSpot.struc;

-            if (newSpot->shapeMethod == "IND") {
+            if (newSpot.shapeMethod == "IND") {
                 r->shapeMethod = 0;
-            } else if (newSpot->shapeMethod == "SYM") {
+            } else if (newSpot.shapeMethod == "SYM") {
                 r->shapeMethod = 1;
-            } else if (newSpot->shapeMethod == "INDSL") {
+            } else if (newSpot.shapeMethod == "INDSL") {
                 r->shapeMethod = 2;
             } else {
                 r->shapeMethod = 3;
             }

-            r->locX = newSpot->locX;
-            r->locXL = newSpot->locXL;
-            r->locY = newSpot->locY;
-            r->locYT = newSpot->locYT;
-            r->centerX = newSpot->centerX;
-            r->centerY = newSpot->centerY;
-            r->circrad = newSpot->circrad;
+            r->locX = newSpot.locX;
+            r->locXL = newSpot.locXL;
+            r->locY = newSpot.locY;
+            r->locYT = newSpot.locYT;
+            r->centerX = newSpot.centerX;
+            r->centerY = newSpot.centerY;
+            r->circrad = newSpot.circrad;

-            if (newSpot->qualityMethod == "enh") {
+            if (newSpot.qualityMethod == "enh") {
                 r->qualityMethod = 0;
             } else {
                 r->qualityMethod = 1;
             }

-            r->transit = newSpot->transit;
-            r->thresh = newSpot->thresh;
-            r->iter = newSpot->iter;
-            r->balan = newSpot->balan;
-            r->transitweak = newSpot->transitweak;
-            r->avoid = newSpot->avoid;
+            r->transit = newSpot.transit;
+            r->thresh = newSpot.thresh;
+            r->iter = newSpot.iter;
+            r->balan = newSpot.balan;
+            r->transitweak = newSpot.transitweak;
+            r->avoid = newSpot.avoid;
             expsettings->addControlSpot(r);

             // ProcParams update
             pp->locallab.nbspot++;
             pp->locallab.selspot = pp->locallab.nbspot - 1;
-            pp->locallab.spots.push_back(*newSpot);
+            pp->locallab.spots.push_back(newSpot);

             // New created spot selection
             expsettings->setSelectedSpot(spotId);
@@ -1421,10 +1417,10 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited)
             disableListener();

             if (pe) {
-                pe->locallab.spots.push_back(new LocallabParamsEdited::LocallabSpotEdited(true));
+                pe->locallab.spots.push_back(LocallabParamsEdited::LocallabSpotEdited(true));
             }

-            updateLocallabGUI(pp, pe, pp->locallab.selspot);
+            updateLocallabGUI(pp, pe.get(), pp->locallab.selspot);

             enableListener();

@@ -1440,7 +1436,7 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited)
                 pedited->locallab.nbspot = true;
                 pedited->locallab.selspot = true;
                 pedited->locallab.id = true;
-                pedited->locallab.spots.push_back(new LocallabParamsEdited::LocallabSpotEdited(true));
+                pedited->locallab.spots.push_back(LocallabParamsEdited::LocallabSpotEdited(true));
             }

             break;
@@ -1471,7 +1467,7 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited)
                         }
                     }

-                    updateLocallabGUI(pp, pe, pp->locallab.selspot);
+                    updateLocallabGUI(pp, pe.get(), pp->locallab.selspot);

                     enableListener();

@@ -1514,7 +1510,7 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited)
             // Update control spots and Locallab tools GUI with selected spot
             expsettings->setSelectedSpot(spotId);
             disableListener();
-            updateLocallabGUI(pp, pe, pp->locallab.selspot);
+            updateLocallabGUI(pp, pe.get(), pp->locallab.selspot);
             enableListener();

             // Update default values according to selected spot
@@ -1527,80 +1523,81 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited)

             break;

-        case (4): // 4 = Spot duplication event
-            newSpot = nullptr;
+        case 4: { // 4 = Spot duplication event
+            bool has_new_spot = false;
             spotId = expsettings->getSelectedSpot();

             for (int i = 0; i < pp->locallab.nbspot && i < (int)pp->locallab.spots.size(); i++) {
                 if (pp->locallab.spots.at(i).id == spotId) {
-                    newSpot = new LocallabParams::LocallabSpot(pp->locallab.spots.at(i));
+                    newSpot = pp->locallab.spots.at(i);
+                    has_new_spot = true;
                     break;
                 }
             }

-            if (!newSpot) {
+            if (!has_new_spot) {
                 break;
             }

             // Spot creation (initialization at currently selected spot)
             spotId = expsettings->getNewId();
             r = new ControlSpotPanel::SpotRow();
-            r->id = newSpot->id = spotId;
-            r->name = newSpot->name = newSpot->name + " - " + M("TP_LOCALLAB_DUPLSPOTNAME");
-            r->isvisible = newSpot->isvisible;
+            r->id = newSpot.id = spotId;
+            r->name = newSpot.name = newSpot.name + " - " + M("TP_LOCALLAB_DUPLSPOTNAME");
+            r->isvisible = newSpot.isvisible;

-            if (newSpot->shape == "ELI") {
+            if (newSpot.shape == "ELI") {
                 r->shape = 0;
             } else {
                 r->shape = 1;
             }

-            if (newSpot->spotMethod == "norm") {
+            if (newSpot.spotMethod == "norm") {
                 r->spotMethod = 0;
             } else {
                 r->spotMethod = 1;
             }

-            r->sensiexclu = newSpot->sensiexclu;
-            r->structexclu = newSpot->structexclu;
-            r->struc = newSpot->struc;
+            r->sensiexclu = newSpot.sensiexclu;
+            r->structexclu = newSpot.structexclu;
+            r->struc = newSpot.struc;

-            if (newSpot->shapeMethod == "IND") {
+            if (newSpot.shapeMethod == "IND") {
                 r->shapeMethod = 0;
-            } else if (newSpot->shapeMethod == "SYM") {
+            } else if (newSpot.shapeMethod == "SYM") {
                 r->shapeMethod = 1;
-            } else if (newSpot->shapeMethod == "INDSL") {
+            } else if (newSpot.shapeMethod == "INDSL") {
                 r->shapeMethod = 2;
             } else {
                 r->shapeMethod = 3;
             }

-            r->locX = newSpot->locX;
-            r->locXL = newSpot->locXL;
-            r->locY = newSpot->locY;
-            r->locYT = newSpot->locYT;
-            r->centerX = newSpot->centerX;
-            r->centerY = newSpot->centerY;
-            r->circrad = newSpot->circrad;
+            r->locX = newSpot.locX;
+            r->locXL = newSpot.locXL;
+            r->locY = newSpot.locY;
+            r->locYT = newSpot.locYT;
+            r->centerX = newSpot.centerX;
+            r->centerY = newSpot.centerY;
+            r->circrad = newSpot.circrad;

-            if (newSpot->qualityMethod == "enh") {
+            if (newSpot.qualityMethod == "enh") {
                 r->qualityMethod = 0;
             } else {
                 r->qualityMethod = 1;
             }

-            r->transit = newSpot->transit;
-            r->thresh = newSpot->thresh;
-            r->iter = newSpot->iter;
-            r->balan = newSpot->balan;
-            r->transitweak = newSpot->transitweak;
-            r->avoid = newSpot->avoid;
+            r->transit = newSpot.transit;
+            r->thresh = newSpot.thresh;
+            r->iter = newSpot.iter;
+            r->balan = newSpot.balan;
+            r->transitweak = newSpot.transitweak;
+            r->avoid = newSpot.avoid;
             expsettings->addControlSpot(r);

             // ProcParams update
             pp->locallab.nbspot++;
             pp->locallab.selspot = pp->locallab.nbspot - 1;
-            pp->locallab.spots.push_back(*newSpot);
+            pp->locallab.spots.push_back(newSpot);

             // New created spot selection
             expsettings->setSelectedSpot(spotId);
@@ -1609,10 +1606,10 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited)
             disableListener();

             if (pe) {
-                pe->locallab.spots.push_back(new LocallabParamsEdited::LocallabSpotEdited(true));
+                pe->locallab.spots.push_back(LocallabParamsEdited::LocallabSpotEdited(true));
             }

-            updateLocallabGUI(pp, pe, pp->locallab.selspot);
+            updateLocallabGUI(pp, pe.get(), pp->locallab.selspot);

             enableListener();

@@ -1624,10 +1621,11 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited)
                 pedited->locallab.nbspot = true;
                 pedited->locallab.selspot = true;
                 pedited->locallab.id = true;
-                pedited->locallab.spots.push_back(new LocallabParamsEdited::LocallabSpotEdited(true));
+                pedited->locallab.spots.push_back(LocallabParamsEdited::LocallabSpotEdited(true));
             }

             break;
+        }

         default: // Spot or locallab GUI updated
             if (pp->locallab.nbspot > 0) {
@@ -2970,9 +2968,9 @@ void Locallab::setDefaults(const rtengine::procparams::ProcParams* defParams, co
     defpedited = pedited;

     if (pedited) {
-        pe = new ParamsEdited(*pedited);
+        pe.reset(new ParamsEdited(*pedited));
     } else {
-        pe = nullptr;
+        pe.reset();
     }
 }

@@ -2995,117 +2993,117 @@ void Locallab::setDefaults(const ProcParams * defParams, const ParamsEdited * pe
     }

     // Set default values for adjusters
-    const LocallabParams::LocallabSpot* defSpot = new LocallabParams::LocallabSpot();
+    LocallabParams::LocallabSpot defSpot;

     if (index != -1 && index < (int)defParams->locallab.spots.size()) {
-        defSpot = &defParams->locallab.spots.at(index);
+        defSpot = defParams->locallab.spots.at(index);
     }

     // Color & Light
-    lightness->setDefault((double)defSpot->lightness);
-    contrast->setDefault((double)defSpot->contrast);
-    chroma->setDefault((double)defSpot->chroma);
-    labgrid->setDefault(defSpot->labgridALow / LocallabParams::LABGRIDL_CORR_MAX, defSpot->labgridBLow / LocallabParams::LABGRIDL_CORR_MAX, defSpot->labgridAHigh / LocallabParams::LABGRIDL_CORR_MAX, defSpot->labgridBHigh / LocallabParams::LABGRIDL_CORR_MAX);
-    sensi->setDefault((double)defSpot->sensi);
-    structcol->setDefault((double)defSpot->structcol);
-    blurcolde->setDefault((double)defSpot->blurcolde);
-    blendmaskcol->setDefault((double)defSpot->blendmaskcol);
-    radmaskcol->setDefault(defSpot->radmaskcol);
-    chromaskcol->setDefault(defSpot->chromaskcol);
-    gammaskcol->setDefault(defSpot->gammaskcol);
-    slomaskcol->setDefault(defSpot->slomaskcol);
-    softradiuscol->setDefault(defSpot->softradiuscol);
+    lightness->setDefault((double)defSpot.lightness);
+    contrast->setDefault((double)defSpot.contrast);
+    chroma->setDefault((double)defSpot.chroma);
+    labgrid->setDefault(defSpot.labgridALow / LocallabParams::LABGRIDL_CORR_MAX, defSpot.labgridBLow / LocallabParams::LABGRIDL_CORR_MAX, defSpot.labgridAHigh / LocallabParams::LABGRIDL_CORR_MAX, defSpot.labgridBHigh / LocallabParams::LABGRIDL_CORR_MAX);
+    sensi->setDefault((double)defSpot.sensi);
+    structcol->setDefault((double)defSpot.structcol);
+    blurcolde->setDefault((double)defSpot.blurcolde);
+    blendmaskcol->setDefault((double)defSpot.blendmaskcol);
+    radmaskcol->setDefault(defSpot.radmaskcol);
+    chromaskcol->setDefault(defSpot.chromaskcol);
+    gammaskcol->setDefault(defSpot.gammaskcol);
+    slomaskcol->setDefault(defSpot.slomaskcol);
+    softradiuscol->setDefault(defSpot.softradiuscol);
     // Exposure
-    expcomp->setDefault(defSpot->expcomp);
-    hlcompr->setDefault((double)defSpot->hlcompr);
-    hlcomprthresh->setDefault((double)defSpot->hlcomprthresh);
-    black->setDefault((double)defSpot->black);
-    shcompr->setDefault((double)defSpot->shcompr);
-    expchroma->setDefault((double)defSpot->expchroma);
-    warm->setDefault((double)defSpot->warm);
-    sensiex->setDefault((double)defSpot->sensiex);
-    structexp->setDefault((double)defSpot->structexp);
-    blurexpde->setDefault((double)defSpot->blurexpde);
-    blendmaskexp->setDefault((double)defSpot->blendmaskexp);
-    radmaskexp->setDefault(defSpot->radmaskexp);
-    chromaskexp->setDefault(defSpot->chromaskexp);
-    gammaskexp->setDefault(defSpot->gammaskexp);
-    slomaskexp->setDefault(defSpot->slomaskexp);
-    softradiusexp->setDefault(defSpot->softradiusexp);
+    expcomp->setDefault(defSpot.expcomp);
+    hlcompr->setDefault((double)defSpot.hlcompr);
+    hlcomprthresh->setDefault((double)defSpot.hlcomprthresh);
+    black->setDefault((double)defSpot.black);
+    shcompr->setDefault((double)defSpot.shcompr);
+    expchroma->setDefault((double)defSpot.expchroma);
+    warm->setDefault((double)defSpot.warm);
+    sensiex->setDefault((double)defSpot.sensiex);
+    structexp->setDefault((double)defSpot.structexp);
+    blurexpde->setDefault((double)defSpot.blurexpde);
+    blendmaskexp->setDefault((double)defSpot.blendmaskexp);
+    radmaskexp->setDefault(defSpot.radmaskexp);
+    chromaskexp->setDefault(defSpot.chromaskexp);
+    gammaskexp->setDefault(defSpot.gammaskexp);
+    slomaskexp->setDefault(defSpot.slomaskexp);
+    softradiusexp->setDefault(defSpot.softradiusexp);
     // Shadow highlight
-    highlights->setDefault((double)defSpot->highlights);
-    h_tonalwidth->setDefault((double)defSpot->h_tonalwidth);
-    shadows->setDefault((double)defSpot->shadows);
-    s_tonalwidth->setDefault((double)defSpot->s_tonalwidth);
-    sh_radius->setDefault((double)defSpot->sh_radius);
-    sensihs->setDefault((double)defSpot->sensihs);
-    blendmaskSH->setDefault((double)defSpot->blendmaskSH);
-    radmaskSH->setDefault(defSpot->radmaskSH);
-    blurSHde->setDefault((double)defSpot->blurSHde);
-    chromaskSH->setDefault(defSpot->chromaskSH);
-    gammaskSH->setDefault(defSpot->gammaskSH);
-    slomaskSH->setDefault(defSpot->slomaskSH);
+    highlights->setDefault((double)defSpot.highlights);
+    h_tonalwidth->setDefault((double)defSpot.h_tonalwidth);
+    shadows->setDefault((double)defSpot.shadows);
+    s_tonalwidth->setDefault((double)defSpot.s_tonalwidth);
+    sh_radius->setDefault((double)defSpot.sh_radius);
+    sensihs->setDefault((double)defSpot.sensihs);
+    blendmaskSH->setDefault((double)defSpot.blendmaskSH);
+    radmaskSH->setDefault(defSpot.radmaskSH);
+    blurSHde->setDefault((double)defSpot.blurSHde);
+    chromaskSH->setDefault(defSpot.chromaskSH);
+    gammaskSH->setDefault(defSpot.gammaskSH);
+    slomaskSH->setDefault(defSpot.slomaskSH);
     // Vibrance
-    saturated->setDefault((double)defSpot->saturated);
-    pastels->setDefault((double)defSpot->pastels);
-    psThreshold->setDefault<int>(defSpot->psthreshold);
-    sensiv->setDefault((double)defSpot->sensiv);
+    saturated->setDefault((double)defSpot.saturated);
+    pastels->setDefault((double)defSpot.pastels);
+    psThreshold->setDefault<int>(defSpot.psthreshold);
+    sensiv->setDefault((double)defSpot.sensiv);
     // Soft Light
-    streng->setDefault((double)defSpot->streng);
-    sensisf->setDefault((double)defSpot->sensisf);
+    streng->setDefault((double)defSpot.streng);
+    sensisf->setDefault((double)defSpot.sensisf);
     // Blur & Noise
-    radius->setDefault(defSpot->radius);
-    strength->setDefault((double)defSpot->strength);
-    sensibn->setDefault((double)defSpot->sensibn);
+    radius->setDefault(defSpot.radius);
+    strength->setDefault((double)defSpot.strength);
+    sensibn->setDefault((double)defSpot.sensibn);
     // Tone Mapping
-    stren->setDefault((double)defSpot->stren);
-    gamma->setDefault((double)defSpot->gamma);
-    estop->setDefault((double)defSpot->estop);
-    scaltm->setDefault((double)defSpot->scaltm);
-    rewei->setDefault((double)defSpot->rewei);
-    sensitm->setDefault((double)defSpot->sensitm);
+    stren->setDefault((double)defSpot.stren);
+    gamma->setDefault((double)defSpot.gamma);
+    estop->setDefault((double)defSpot.estop);
+    scaltm->setDefault((double)defSpot.scaltm);
+    rewei->setDefault((double)defSpot.rewei);
+    sensitm->setDefault((double)defSpot.sensitm);
     // Retinex
-    str->setDefault((double)defSpot->str);
-    chrrt->setDefault((double)defSpot->chrrt);
-    neigh->setDefault((double)defSpot->neigh);
-    vart->setDefault((double)defSpot->vart);
-    dehaz->setDefault((double)defSpot->dehaz);
-    sensih->setDefault((double)defSpot->sensih);
-    softradiusret->setDefault(defSpot->softradiusret);
+    str->setDefault((double)defSpot.str);
+    chrrt->setDefault((double)defSpot.chrrt);
+    neigh->setDefault((double)defSpot.neigh);
+    vart->setDefault((double)defSpot.vart);
+    dehaz->setDefault((double)defSpot.dehaz);
+    sensih->setDefault((double)defSpot.sensih);
+    softradiusret->setDefault(defSpot.softradiusret);
     // Sharpening
-    sharcontrast->setDefault((double)defSpot->sharcontrast);
-    sharradius->setDefault(defSpot->sharradius);
-    sharamount->setDefault((double)defSpot->sharamount);
-    shardamping->setDefault((double)defSpot->shardamping);
-    shariter->setDefault((double)defSpot->shariter);
-    sharblur->setDefault(defSpot->sharblur);
-    sensisha->setDefault((double)defSpot->sensisha);
+    sharcontrast->setDefault((double)defSpot.sharcontrast);
+    sharradius->setDefault(defSpot.sharradius);
+    sharamount->setDefault((double)defSpot.sharamount);
+    shardamping->setDefault((double)defSpot.shardamping);
+    shariter->setDefault((double)defSpot.shariter);
+    sharblur->setDefault(defSpot.sharblur);
+    sensisha->setDefault((double)defSpot.sensisha);
     // Local Contrast
-    lcradius->setDefault((double)defSpot->lcradius);
-    lcamount->setDefault(defSpot->lcamount);
-    lcdarkness->setDefault(defSpot->lcdarkness);
-    lclightness->setDefault(defSpot->lclightness);
-    sensilc->setDefault((double)defSpot->sensilc);
+    lcradius->setDefault((double)defSpot.lcradius);
+    lcamount->setDefault(defSpot.lcamount);
+    lcdarkness->setDefault(defSpot.lcdarkness);
+    lclightness->setDefault(defSpot.lclightness);
+    sensilc->setDefault((double)defSpot.sensilc);
     // Contrast by detail levels
     for (int i = 0; i < 5; i++) {
-        multiplier[i]->setDefault(defSpot->mult[i]);
+        multiplier[i]->setDefault(defSpot.mult[i]);
     }

-    chromacbdl->setDefault((double)defSpot->chromacbdl);
-    threshold->setDefault(defSpot->threshold);
-    sensicb->setDefault((double)defSpot->sensicb);
-    softradiuscb->setDefault(defSpot->softradiuscb);
+    chromacbdl->setDefault((double)defSpot.chromacbdl);
+    threshold->setDefault(defSpot.threshold);
+    sensicb->setDefault((double)defSpot.sensicb);
+    softradiuscb->setDefault(defSpot.softradiuscb);
     // Denoise
-    noiselumf->setDefault((double)defSpot->noiselumf);
-    noiselumc->setDefault((double)defSpot->noiselumc);
-    noiselumdetail->setDefault((double)defSpot->noiselumdetail);
-    noiselequal->setDefault((double)defSpot->noiselequal);
-    noisechrof->setDefault((double)defSpot->noisechrof);
-    noisechroc->setDefault((double)defSpot->noisechroc);
-    noisechrodetail->setDefault((double)defSpot->noisechrodetail);
-    adjblur->setDefault((double)defSpot->adjblur);
-    bilateral->setDefault((double)defSpot->bilateral);
-    sensiden->setDefault((double)defSpot->sensiden);
+    noiselumf->setDefault((double)defSpot.noiselumf);
+    noiselumc->setDefault((double)defSpot.noiselumc);
+    noiselumdetail->setDefault((double)defSpot.noiselumdetail);
+    noiselequal->setDefault((double)defSpot.noiselequal);
+    noisechrof->setDefault((double)defSpot.noisechrof);
+    noisechroc->setDefault((double)defSpot.noisechroc);
+    noisechrodetail->setDefault((double)defSpot.noisechrodetail);
+    adjblur->setDefault((double)defSpot.adjblur);
+    bilateral->setDefault((double)defSpot.bilateral);
+    sensiden->setDefault((double)defSpot.sensiden);

     // Set default edited states for adjusters and threshold adjusters
     if (!pedited) {
@@ -3116,7 +3114,7 @@ void Locallab::setDefaults(const ProcParams * defParams, const ParamsEdited * pe
         labgrid->setEdited(Edited);
         sensi->setDefaultEditedState(Irrelevant);
         structcol->setDefaultEditedState(Irrelevant);
-        strengthgrid->setDefault((double)defSpot->strengthgrid);
+        strengthgrid->setDefault((double)defSpot.strengthgrid);
         blurcolde->setDefaultEditedState(Irrelevant);
         blendmaskcol->setDefaultEditedState(Irrelevant);
         radmaskcol->setDefaultEditedState(Irrelevant);
@@ -3216,118 +3214,118 @@ void Locallab::setDefaults(const ProcParams * defParams, const ParamsEdited * pe
         bilateral->setDefaultEditedState(Irrelevant);
         sensiden->setDefaultEditedState(Irrelevant);
     } else {
-        const LocallabParamsEdited::LocallabSpotEdited* defSpotState = new LocallabParamsEdited::LocallabSpotEdited(true);
+        LocallabParamsEdited::LocallabSpotEdited defSpotState(true);

         if (index != 1 && index < (int)pedited->locallab.spots.size()) {
-            defSpotState = &pedited->locallab.spots.at(index);
+            defSpotState = pedited->locallab.spots.at(index);
         }

         // Color & Light
-        lightness->setDefaultEditedState(defSpotState->lightness ? Edited : UnEdited);
-        contrast->setDefaultEditedState(defSpotState->contrast ? Edited : UnEdited);
-        chroma->setDefaultEditedState(defSpotState->chroma ? Edited : UnEdited);
-        labgrid->setEdited((defSpotState->labgridALow || defSpotState->labgridBLow || defSpotState->labgridAHigh || defSpotState->labgridBHigh) ? Edited : UnEdited);
-        sensi->setDefaultEditedState(defSpotState->sensi ? Edited : UnEdited);
-        structcol->setDefaultEditedState(defSpotState->structcol ? Edited : UnEdited);
-        strengthgrid->setDefaultEditedState(defSpotState->strengthgrid ? Edited : UnEdited);
-        blurcolde->setDefaultEditedState(defSpotState->blurcolde ? Edited : UnEdited);
-        blendmaskcol->setDefaultEditedState(defSpotState->blendmaskcol ? Edited : UnEdited);
-        radmaskcol->setDefaultEditedState(defSpotState->radmaskcol ? Edited : UnEdited);
-        chromaskcol->setDefaultEditedState(defSpotState->chromaskcol ? Edited : UnEdited);
-        gammaskcol->setDefaultEditedState(defSpotState->gammaskcol ? Edited : UnEdited);
-        slomaskcol->setDefaultEditedState(defSpotState->slomaskcol ? Edited : UnEdited);
-        softradiuscol->setDefaultEditedState(defSpotState->softradiuscol ? Edited : UnEdited);
+        lightness->setDefaultEditedState(defSpotState.lightness ? Edited : UnEdited);
+        contrast->setDefaultEditedState(defSpotState.contrast ? Edited : UnEdited);
+        chroma->setDefaultEditedState(defSpotState.chroma ? Edited : UnEdited);
+        labgrid->setEdited((defSpotState.labgridALow || defSpotState.labgridBLow || defSpotState.labgridAHigh || defSpotState.labgridBHigh) ? Edited : UnEdited);
+        sensi->setDefaultEditedState(defSpotState.sensi ? Edited : UnEdited);
+        structcol->setDefaultEditedState(defSpotState.structcol ? Edited : UnEdited);
+        strengthgrid->setDefaultEditedState(defSpotState.strengthgrid ? Edited : UnEdited);
+        blurcolde->setDefaultEditedState(defSpotState.blurcolde ? Edited : UnEdited);
+        blendmaskcol->setDefaultEditedState(defSpotState.blendmaskcol ? Edited : UnEdited);
+        radmaskcol->setDefaultEditedState(defSpotState.radmaskcol ? Edited : UnEdited);
+        chromaskcol->setDefaultEditedState(defSpotState.chromaskcol ? Edited : UnEdited);
+        gammaskcol->setDefaultEditedState(defSpotState.gammaskcol ? Edited : UnEdited);
+        slomaskcol->setDefaultEditedState(defSpotState.slomaskcol ? Edited : UnEdited);
+        softradiuscol->setDefaultEditedState(defSpotState.softradiuscol ? Edited : UnEdited);
         // Exposure
-        expcomp->setDefaultEditedState(defSpotState->expcomp ? Edited : UnEdited);
-        hlcompr->setDefaultEditedState(defSpotState->hlcompr ? Edited : UnEdited);
-        hlcomprthresh->setDefaultEditedState(defSpotState->hlcomprthresh ? Edited : UnEdited);
-        black->setDefaultEditedState(defSpotState->black ? Edited : UnEdited);
-        shcompr->setDefaultEditedState(defSpotState->shcompr ? Edited : UnEdited);
-        expchroma->setDefaultEditedState(defSpotState->expchroma ? Edited : UnEdited);
-        warm->setDefaultEditedState(defSpotState->warm ? Edited : UnEdited);
-        sensiex->setDefaultEditedState(defSpotState->sensiex ? Edited : UnEdited);
-        structexp->setDefaultEditedState(defSpotState->structexp ? Edited : UnEdited);
-        blurexpde->setDefaultEditedState(defSpotState->blurexpde ? Edited : UnEdited);
-        blendmaskexp->setDefaultEditedState(defSpotState->blendmaskexp ? Edited : UnEdited);
-        radmaskexp->setDefaultEditedState(defSpotState->radmaskexp ? Edited : UnEdited);
-        chromaskexp->setDefaultEditedState(defSpotState->chromaskexp ? Edited : UnEdited);
-        gammaskexp->setDefaultEditedState(defSpotState->gammaskexp ? Edited : UnEdited);
-        slomaskexp->setDefaultEditedState(defSpotState->slomaskexp ? Edited : UnEdited);
-        softradiusexp->setDefaultEditedState(defSpotState->softradiusexp ? Edited : UnEdited);
+        expcomp->setDefaultEditedState(defSpotState.expcomp ? Edited : UnEdited);
+        hlcompr->setDefaultEditedState(defSpotState.hlcompr ? Edited : UnEdited);
+        hlcomprthresh->setDefaultEditedState(defSpotState.hlcomprthresh ? Edited : UnEdited);
+        black->setDefaultEditedState(defSpotState.black ? Edited : UnEdited);
+        shcompr->setDefaultEditedState(defSpotState.shcompr ? Edited : UnEdited);
+        expchroma->setDefaultEditedState(defSpotState.expchroma ? Edited : UnEdited);
+        warm->setDefaultEditedState(defSpotState.warm ? Edited : UnEdited);
+        sensiex->setDefaultEditedState(defSpotState.sensiex ? Edited : UnEdited);
+        structexp->setDefaultEditedState(defSpotState.structexp ? Edited : UnEdited);
+        blurexpde->setDefaultEditedState(defSpotState.blurexpde ? Edited : UnEdited);
+        blendmaskexp->setDefaultEditedState(defSpotState.blendmaskexp ? Edited : UnEdited);
+        radmaskexp->setDefaultEditedState(defSpotState.radmaskexp ? Edited : UnEdited);
+        chromaskexp->setDefaultEditedState(defSpotState.chromaskexp ? Edited : UnEdited);
+        gammaskexp->setDefaultEditedState(defSpotState.gammaskexp ? Edited : UnEdited);
+        slomaskexp->setDefaultEditedState(defSpotState.slomaskexp ? Edited : UnEdited);
+        softradiusexp->setDefaultEditedState(defSpotState.softradiusexp ? Edited : UnEdited);
         // Shadow highlight
-        highlights->setDefaultEditedState(defSpotState->highlights ? Edited : UnEdited);
-        h_tonalwidth->setDefaultEditedState(defSpotState->h_tonalwidth ? Edited : UnEdited);
-        shadows->setDefaultEditedState(defSpotState->shadows ? Edited : UnEdited);
-        s_tonalwidth->setDefaultEditedState(defSpotState->s_tonalwidth ? Edited : UnEdited);
-        sh_radius->setDefaultEditedState(defSpotState->sh_radius ? Edited : UnEdited);
-        sensihs->setDefaultEditedState(defSpotState->sensihs ? Edited : UnEdited);
-        blendmaskSH->setDefaultEditedState(defSpotState->blendmaskSH ? Edited : UnEdited);
-        radmaskSH->setDefaultEditedState(defSpotState->radmaskSH ? Edited : UnEdited);
-        blurSHde->setDefaultEditedState(defSpotState->blurSHde ? Edited : UnEdited);
-        chromaskSH->setDefaultEditedState(defSpotState->chromaskSH ? Edited : UnEdited);
-        gammaskSH->setDefaultEditedState(defSpotState->gammaskSH ? Edited : UnEdited);
-        slomaskSH->setDefaultEditedState(defSpotState->slomaskSH ? Edited : UnEdited);
+        highlights->setDefaultEditedState(defSpotState.highlights ? Edited : UnEdited);
+        h_tonalwidth->setDefaultEditedState(defSpotState.h_tonalwidth ? Edited : UnEdited);
+        shadows->setDefaultEditedState(defSpotState.shadows ? Edited : UnEdited);
+        s_tonalwidth->setDefaultEditedState(defSpotState.s_tonalwidth ? Edited : UnEdited);
+        sh_radius->setDefaultEditedState(defSpotState.sh_radius ? Edited : UnEdited);
+        sensihs->setDefaultEditedState(defSpotState.sensihs ? Edited : UnEdited);
+        blendmaskSH->setDefaultEditedState(defSpotState.blendmaskSH ? Edited : UnEdited);
+        radmaskSH->setDefaultEditedState(defSpotState.radmaskSH ? Edited : UnEdited);
+        blurSHde->setDefaultEditedState(defSpotState.blurSHde ? Edited : UnEdited);
+        chromaskSH->setDefaultEditedState(defSpotState.chromaskSH ? Edited : UnEdited);
+        gammaskSH->setDefaultEditedState(defSpotState.gammaskSH ? Edited : UnEdited);
+        slomaskSH->setDefaultEditedState(defSpotState.slomaskSH ? Edited : UnEdited);
         // Vibrance
-        saturated->setDefaultEditedState(defSpotState->saturated ? Edited : UnEdited);
-        pastels->setDefaultEditedState(defSpotState->pastels ? Edited : UnEdited);
-        psThreshold->setDefaultEditedState(defSpotState->psthreshold ? Edited : UnEdited);
-        sensiv->setDefaultEditedState(defSpotState->sensiv ? Edited : UnEdited);
+        saturated->setDefaultEditedState(defSpotState.saturated ? Edited : UnEdited);
+        pastels->setDefaultEditedState(defSpotState.pastels ? Edited : UnEdited);
+        psThreshold->setDefaultEditedState(defSpotState.psthreshold ? Edited : UnEdited);
+        sensiv->setDefaultEditedState(defSpotState.sensiv ? Edited : UnEdited);
         // Soft Light
-        streng->setDefaultEditedState(defSpotState->streng ? Edited : UnEdited);
-        sensisf->setDefaultEditedState(defSpotState->sensisf ? Edited : UnEdited);
+        streng->setDefaultEditedState(defSpotState.streng ? Edited : UnEdited);
+        sensisf->setDefaultEditedState(defSpotState.sensisf ? Edited : UnEdited);
         // Blur & Noise
-        radius->setDefaultEditedState(defSpotState->radius ? Edited : UnEdited);
-        strength->setDefaultEditedState(defSpotState->strength ? Edited : UnEdited);
-        sensibn->setDefaultEditedState(defSpotState->sensibn ? Edited : UnEdited);
+        radius->setDefaultEditedState(defSpotState.radius ? Edited : UnEdited);
+        strength->setDefaultEditedState(defSpotState.strength ? Edited : UnEdited);
+        sensibn->setDefaultEditedState(defSpotState.sensibn ? Edited : UnEdited);
         // Tone Mapping
-        stren->setDefaultEditedState(defSpotState->stren ? Edited : UnEdited);
-        gamma->setDefaultEditedState(defSpotState->gamma ? Edited : UnEdited);
-        estop->setDefaultEditedState(defSpotState->estop ? Edited : UnEdited);
-        scaltm->setDefaultEditedState(defSpotState->scaltm ? Edited : UnEdited);
-        rewei->setDefaultEditedState(defSpotState->rewei ? Edited : UnEdited);
-        sensitm->setDefaultEditedState(defSpotState->sensitm ? Edited : UnEdited);
+        stren->setDefaultEditedState(defSpotState.stren ? Edited : UnEdited);
+        gamma->setDefaultEditedState(defSpotState.gamma ? Edited : UnEdited);
+        estop->setDefaultEditedState(defSpotState.estop ? Edited : UnEdited);
+        scaltm->setDefaultEditedState(defSpotState.scaltm ? Edited : UnEdited);
+        rewei->setDefaultEditedState(defSpotState.rewei ? Edited : UnEdited);
+        sensitm->setDefaultEditedState(defSpotState.sensitm ? Edited : UnEdited);
         // Retinex
-        str->setDefaultEditedState(defSpotState->str ? Edited : UnEdited);
-        chrrt->setDefaultEditedState(defSpotState->chrrt ? Edited : UnEdited);
-        neigh->setDefaultEditedState(defSpotState->neigh ? Edited : UnEdited);
-        vart->setDefaultEditedState(defSpotState->vart ? Edited : UnEdited);
-        dehaz->setDefaultEditedState(defSpotState->dehaz ? Edited : UnEdited);
-        sensih->setDefaultEditedState(defSpotState->sensih ? Edited : UnEdited);
-        softradiusret->setDefaultEditedState(defSpotState->softradiusret ? Edited : UnEdited);
+        str->setDefaultEditedState(defSpotState.str ? Edited : UnEdited);
+        chrrt->setDefaultEditedState(defSpotState.chrrt ? Edited : UnEdited);
+        neigh->setDefaultEditedState(defSpotState.neigh ? Edited : UnEdited);
+        vart->setDefaultEditedState(defSpotState.vart ? Edited : UnEdited);
+        dehaz->setDefaultEditedState(defSpotState.dehaz ? Edited : UnEdited);
+        sensih->setDefaultEditedState(defSpotState.sensih ? Edited : UnEdited);
+        softradiusret->setDefaultEditedState(defSpotState.softradiusret ? Edited : UnEdited);
         // Sharpening
-        sharcontrast->setDefaultEditedState(defSpotState->sharcontrast ? Edited : UnEdited);
-        sharradius->setDefaultEditedState(defSpotState->sharradius ? Edited : UnEdited);
-        sharamount->setDefaultEditedState(defSpotState->sharamount ? Edited : UnEdited);
-        shardamping->setDefaultEditedState(defSpotState->shardamping ? Edited : UnEdited);
-        shariter->setDefaultEditedState(defSpotState->shariter ? Edited : UnEdited);
-        sharblur->setDefaultEditedState(defSpotState->sharblur ? Edited : UnEdited);
-        sensisha->setDefaultEditedState(defSpotState->sensisha ? Edited : UnEdited);
+        sharcontrast->setDefaultEditedState(defSpotState.sharcontrast ? Edited : UnEdited);
+        sharradius->setDefaultEditedState(defSpotState.sharradius ? Edited : UnEdited);
+        sharamount->setDefaultEditedState(defSpotState.sharamount ? Edited : UnEdited);
+        shardamping->setDefaultEditedState(defSpotState.shardamping ? Edited : UnEdited);
+        shariter->setDefaultEditedState(defSpotState.shariter ? Edited : UnEdited);
+        sharblur->setDefaultEditedState(defSpotState.sharblur ? Edited : UnEdited);
+        sensisha->setDefaultEditedState(defSpotState.sensisha ? Edited : UnEdited);
         // Local Contrast
-        lcradius->setDefaultEditedState(defSpotState->lcradius ? Edited : UnEdited);
-        lcamount->setDefaultEditedState(defSpotState->lcamount ? Edited : UnEdited);
-        lcdarkness->setDefaultEditedState(defSpotState->lcdarkness ? Edited : UnEdited);
-        lclightness->setDefaultEditedState(defSpotState->lclightness ? Edited : UnEdited);
-        sensilc->setDefaultEditedState(defSpotState->sensilc ? Edited : UnEdited);
+        lcradius->setDefaultEditedState(defSpotState.lcradius ? Edited : UnEdited);
+        lcamount->setDefaultEditedState(defSpotState.lcamount ? Edited : UnEdited);
+        lcdarkness->setDefaultEditedState(defSpotState.lcdarkness ? Edited : UnEdited);
+        lclightness->setDefaultEditedState(defSpotState.lclightness ? Edited : UnEdited);
+        sensilc->setDefaultEditedState(defSpotState.sensilc ? Edited : UnEdited);
         // Contrast by detail levels
         for (int i = 0; i < 5; i++) {
-            multiplier[i]->setDefaultEditedState(defSpotState->mult[i] ? Edited : UnEdited);
+            multiplier[i]->setDefaultEditedState(defSpotState.mult[i] ? Edited : UnEdited);
         }

-        chromacbdl->setDefaultEditedState(defSpotState->chromacbdl ? Edited : UnEdited);
-        threshold->setDefaultEditedState(defSpotState->threshold ? Edited : UnEdited);
-        sensicb->setDefaultEditedState(defSpotState->sensicb ? Edited : UnEdited);
-        softradiuscb->setDefaultEditedState(defSpotState->softradiuscb ? Edited : UnEdited);
+        chromacbdl->setDefaultEditedState(defSpotState.chromacbdl ? Edited : UnEdited);
+        threshold->setDefaultEditedState(defSpotState.threshold ? Edited : UnEdited);
+        sensicb->setDefaultEditedState(defSpotState.sensicb ? Edited : UnEdited);
+        softradiuscb->setDefaultEditedState(defSpotState.softradiuscb ? Edited : UnEdited);
         // Denoise
-        noiselumf->setDefaultEditedState(defSpotState->noiselumf ? Edited : UnEdited);
-        noiselumc->setDefaultEditedState(defSpotState->noiselumc ? Edited : UnEdited);
-        noiselumdetail->setDefaultEditedState(defSpotState->noiselumdetail ? Edited : UnEdited);
-        noiselequal->setDefaultEditedState(defSpotState->noiselequal ? Edited : UnEdited);
-        noisechrof->setDefaultEditedState(defSpotState->noisechrof ? Edited : UnEdited);
-        noisechroc->setDefaultEditedState(defSpotState->noisechroc ? Edited : UnEdited);
-        noisechrodetail->setDefaultEditedState(defSpotState->noisechrodetail ? Edited : UnEdited);
-        adjblur->setDefaultEditedState(defSpotState->adjblur ? Edited : UnEdited);
-        bilateral->setDefaultEditedState(defSpotState->bilateral ? Edited : UnEdited);
-        sensiden->setDefaultEditedState(defSpotState->sensiden ? Edited : UnEdited);
+        noiselumf->setDefaultEditedState(defSpotState.noiselumf ? Edited : UnEdited);
+        noiselumc->setDefaultEditedState(defSpotState.noiselumc ? Edited : UnEdited);
+        noiselumdetail->setDefaultEditedState(defSpotState.noiselumdetail ? Edited : UnEdited);
+        noiselequal->setDefaultEditedState(defSpotState.noiselequal ? Edited : UnEdited);
+        noisechrof->setDefaultEditedState(defSpotState.noisechrof ? Edited : UnEdited);
+        noisechroc->setDefaultEditedState(defSpotState.noisechroc ? Edited : UnEdited);
+        noisechrodetail->setDefaultEditedState(defSpotState.noisechrodetail ? Edited : UnEdited);
+        adjblur->setDefaultEditedState(defSpotState.adjblur ? Edited : UnEdited);
+        bilateral->setDefaultEditedState(defSpotState.bilateral ? Edited : UnEdited);
+        sensiden->setDefaultEditedState(defSpotState.sensiden ? Edited : UnEdited);
     }
 }

@@ -4546,37 +4544,37 @@ void Locallab::updateLocallabGUI(const rtengine::procparams::ProcParams* pp, con
                 const LocallabParamsEdited::LocallabSpotEdited* spotState = &pedited->locallab.spots.at(index);

                 // Control spot settings
-                ControlSpotPanel::SpotEdited* const se = new ControlSpotPanel::SpotEdited();
+                ControlSpotPanel::SpotEdited se;

                 if (pedited->locallab.nbspot && pedited->locallab.id) {
-                    se->nbspot = true;
+                    se.nbspot = true;
                 } else {
-                    se->nbspot = false;
+                    se.nbspot = false;
                 }

-                se->selspot = pedited->locallab.selspot;
-                se->name = spotState->name;
-                se->isvisible = spotState->isvisible;
-                se->shape = spotState->shape;
-                se->spotMethod = spotState->spotMethod;
-                se->sensiexclu = spotState->sensiexclu;
-                se->structexclu = spotState->structexclu;
-                se->struc = spotState->struc;
-                se->shapeMethod = spotState->shapeMethod;
-                se->locX = spotState->locX;
-                se->locXL = spotState->locXL;
-                se->locY = spotState->locY;
-                se->locYT = spotState->locYT;
-                se->centerX = spotState->centerX;
-                se->centerY = spotState->centerY;
-                se->circrad = spotState->circrad;
-                se->qualityMethod = spotState->qualityMethod;
-                se->transit = spotState->transit;
-                se->thresh = spotState->thresh;
-                se->iter = spotState->iter;
-                se->balan = spotState->balan;
-                se->transitweak = spotState->transitweak;
-                se->avoid = spotState->avoid;
+                se.selspot = pedited->locallab.selspot;
+                se.name = spotState->name;
+                se.isvisible = spotState->isvisible;
+                se.shape = spotState->shape;
+                se.spotMethod = spotState->spotMethod;
+                se.sensiexclu = spotState->sensiexclu;
+                se.structexclu = spotState->structexclu;
+                se.struc = spotState->struc;
+                se.shapeMethod = spotState->shapeMethod;
+                se.locX = spotState->locX;
+                se.locXL = spotState->locXL;
+                se.locY = spotState->locY;
+                se.locYT = spotState->locYT;
+                se.centerX = spotState->centerX;
+                se.centerY = spotState->centerY;
+                se.circrad = spotState->circrad;
+                se.qualityMethod = spotState->qualityMethod;
+                se.transit = spotState->transit;
+                se.thresh = spotState->thresh;
+                se.iter = spotState->iter;
+                se.balan = spotState->balan;
+                se.transitweak = spotState->transitweak;
+                se.avoid = spotState->avoid;
                 expsettings->setEditedStates(se);

                 // Color & Light
diff --git a/rtgui/locallab.h b/rtgui/locallab.h
index 660063d84..8d151c808 100644
--- a/rtgui/locallab.h
+++ b/rtgui/locallab.h
@@ -20,7 +20,10 @@
  *  2018 Pierre Cabrera <[email protected]>
  */

+#include <memory>
+
 #include <gtkmm.h>
+
 #include "adjuster.h"
 #include "toolpanel.h"
 #include "editcallbacks.h"
@@ -278,7 +281,7 @@ private:
      * Used to store the default ParamsEdited when setDefaults function is called
      * This ParamsEdited is updated when control spots are modified and is used to update adjusters edited state
      */
-    ParamsEdited* pe;
+    std::unique_ptr<ParamsEdited> pe;

     // Expander management functions
     void foldAllButMe(GdkEventButton* event, MyExpander *expander);
diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc
index df2037dba..475cf8eac 100644
--- a/rtgui/paramsedited.cc
+++ b/rtgui/paramsedited.cc
@@ -611,7 +611,7 @@ void ParamsEdited::initFrom(const std::vector<rtengine::procparams::ProcParams>&

     // Resize LocallabSpotEdited according to src[0]
     locallab.spots.clear();
-    locallab.spots.resize(p.locallab.nbspot, new LocallabParamsEdited::LocallabSpotEdited(true));
+    locallab.spots.resize(p.locallab.nbspot, LocallabParamsEdited::LocallabSpotEdited(true));

     for (size_t i = 1; i < src.size(); i++) {
         const ProcParams& other = src[i];
@@ -1111,7 +1111,7 @@ void ParamsEdited::initFrom(const std::vector<rtengine::procparams::ProcParams>&
             // locallab.id and locallab.spots are set to false because cannot be combined
             locallab.id = false;
             locallab.spots.clear();
-            locallab.spots.resize(p.locallab.nbspot, new LocallabParamsEdited::LocallabSpotEdited(false));
+            locallab.spots.resize(p.locallab.nbspot, LocallabParamsEdited::LocallabSpotEdited(false));
         }

         pcvignette.enabled = pcvignette.enabled && p.pcvignette.enabled == other.pcvignette.enabled;
@@ -2505,9 +2505,9 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
         toEdit.locallab.spots.clear();

         for (size_t i = 0; i < mods.locallab.spots.size(); i++) {
-            LocallabParams::LocallabSpot *newSpot = new LocallabParams::LocallabSpot();
-            newSpot->id = mods.locallab.spots.at(i).id;
-            toEdit.locallab.spots.push_back(*newSpot);
+            LocallabParams::LocallabSpot newSpot;
+            newSpot.id = mods.locallab.spots.at(i).id;
+            toEdit.locallab.spots.push_back(newSpot);
         }

         // Common spots in tmpLocallab and mods are restored in toEdit
diff --git a/rtgui/profilepanel.cc b/rtgui/profilepanel.cc
index 8781fe97a..af63f47e6 100644
--- a/rtgui/profilepanel.cc
+++ b/rtgui/profilepanel.cc
@@ -591,7 +591,7 @@ void ProfilePanel::paste_clicked (GdkEventButton* event)

             // Setting LocallabSpotEdited number coherent with nbspot number in lastsaved->pparams
             custom->pedited->locallab.spots.clear();
-            custom->pedited->locallab.spots.resize(custom->pparams->locallab.nbspot, new LocallabParamsEdited::LocallabSpotEdited(false));
+            custom->pedited->locallab.spots.resize(custom->pparams->locallab.nbspot, LocallabParamsEdited::LocallabSpotEdited(false));
         } else {
             const ProfileStoreEntry* entry = profiles->getSelectedEntry();

@@ -601,7 +601,7 @@ void ProfilePanel::paste_clicked (GdkEventButton* event)

                 // Setting LocallabSpotEdited number coherent with nbspot number in partProfile->pparams
                 custom->pedited->locallab.spots.clear();
-                custom->pedited->locallab.spots.resize(custom->pparams->locallab.nbspot, new LocallabParamsEdited::LocallabSpotEdited(false));
+                custom->pedited->locallab.spots.resize(custom->pparams->locallab.nbspot, LocallabParamsEdited::LocallabSpotEdited(false));
             }
         }

@@ -619,7 +619,7 @@ void ProfilePanel::paste_clicked (GdkEventButton* event)

                 // Setting LocallabSpotEdited number coherent with nbspot number in lastsaved->pparams
                 custom->pedited->locallab.spots.clear();
-                custom->pedited->locallab.spots.resize(custom->pparams->locallab.nbspot, new LocallabParamsEdited::LocallabSpotEdited(true));
+                custom->pedited->locallab.spots.resize(custom->pparams->locallab.nbspot, LocallabParamsEdited::LocallabSpotEdited(true));
             } else {
                 const ProfileStoreEntry* entry = profiles->getSelectedEntry();

@@ -629,7 +629,7 @@ void ProfilePanel::paste_clicked (GdkEventButton* event)

                     // Setting LocallabSpotEdited number coherent with nbspot number in partProfile->pparams
                     custom->pedited->locallab.spots.clear();
-                    custom->pedited->locallab.spots.resize(custom->pparams->locallab.nbspot, new LocallabParamsEdited::LocallabSpotEdited(true));
+                    custom->pedited->locallab.spots.resize(custom->pparams->locallab.nbspot, LocallabParamsEdited::LocallabSpotEdited(true));
                 }
             }
         }
@@ -676,14 +676,14 @@ void ProfilePanel::paste_clicked (GdkEventButton* event)

             // Setting LocallabSpotEdited number coherent with nbspot number in custom->pparams
             custom->pedited->locallab.spots.clear();
-            custom->pedited->locallab.spots.resize(custom->pparams->locallab.nbspot, new LocallabParamsEdited::LocallabSpotEdited(true));
+            custom->pedited->locallab.spots.resize(custom->pparams->locallab.nbspot, LocallabParamsEdited::LocallabSpotEdited(true));
         } else {
             // custom.pparams = clipboard.pparams non filtered
             *custom->pparams = pp;

             // Setting LocallabSpotEdited number coherent with nbspot number in custom->pparams
             custom->pedited->locallab.spots.clear();
-            custom->pedited->locallab.spots.resize(custom->pparams->locallab.nbspot, new LocallabParamsEdited::LocallabSpotEdited(true));
+            custom->pedited->locallab.spots.resize(custom->pparams->locallab.nbspot, LocallabParamsEdited::LocallabSpotEdited(true));
         }
     }

@@ -733,7 +733,7 @@ void ProfilePanel::selection_changed ()
                 ParamsEdited pe(true);

                 // Setting LocallabSpotEdited number coherent with nbspot number in s->pparams
-                pe.locallab.spots.resize(s->pparams->locallab.nbspot, new LocallabParamsEdited::LocallabSpotEdited(true));
+                pe.locallab.spots.resize(s->pparams->locallab.nbspot, LocallabParamsEdited::LocallabSpotEdited(true));

                 PartialProfile s2(s->pparams, &pe, false);
                 changeTo (&s2, pse->label + "+");
@@ -776,7 +776,7 @@ void ProfilePanel::procParamsChanged(

     // Setting LocallabSpotEdited number coherent with nbspot number in p
     custom->pedited->locallab.spots.clear();
-    custom->pedited->locallab.spots.resize(p->locallab.nbspot, new LocallabParamsEdited::LocallabSpotEdited(true));
+    custom->pedited->locallab.spots.resize(p->locallab.nbspot, LocallabParamsEdited::LocallabSpotEdited(true));
 }

 void ProfilePanel::clearParamChanges()
@@ -813,7 +813,7 @@ void ProfilePanel::initProfile (const Glib::ustring& profileFullPath, ProcParams
     if (lastSaved) {
         ParamsEdited* pe = new ParamsEdited(true);
         // Setting LocallabSpotEdited number coherent with lastSaved->locallab.nbspot (initialized at true such as pe)
-        pe->locallab.spots.resize(lastSaved->locallab.nbspot, new LocallabParamsEdited::LocallabSpotEdited(true));
+        pe->locallab.spots.resize(lastSaved->locallab.nbspot, LocallabParamsEdited::LocallabSpotEdited(true));
         // copying the provided last saved profile to ProfilePanel::lastsaved
         lastsaved = new PartialProfile(lastSaved, pe);
     }

Best,
Flössie

@Floessie

I can not apply the patch. I'm getting error messages
$ git apply flo3.patch, with the code above...I copy in my editor.

"error: le patch a échoué : rtgui/controlspotpanel.cc:1662
error: rtgui/controlspotpanel.cc : le patch ne s'applique pas
error: le patch a échoué : rtgui/controlspotpanel.h:21
error: rtgui/controlspotpanel.h : le patch ne s'applique pas"

But these modifications exceed me (I am a poor computer scientist!) I will let @Pandagrapher give his opinion, it is he who is at the origin of this code

jacques

Hm, then again on filebin. Applies fine here on newlocallab.

@Desmis as I know @Floessie has trouble pushing to git from behind firewalls, I made a branch for you:
newlocallab_plumbing

@Floessie
I test with "filebin", patch apply whitout problem.
But what I miss when you post a patch, what to do exactly ?

For me no differences with and whithout, if I speak behavior "locallab"

@Beep6581 thanks for this branch

jacques

@Desmis I think the problem was with newline characters, which were lost in the copy-pasted patch, so I had to use --ignore-whitespace.

@Beep6581
I test "my" patch with "--ignore-whitespace" and it works

thank you

jacques

@Desmis

But what I miss when you post a patch, what to do exactly ?
For me no differences with and whithout, if I speak behavior "locallab"

Then everything is fine.

I was asked by @heckflosse to take a look at the memory behavior, found a big bunch of leaks in the new code and posted a patch to fix them. There should be no functional difference. If I don't write what to test exactly I assume you check if it still works the way you expect it. That's what you did, so all is fine. :+1:

My question was only for how to manage patch :)
For the goal of this patch, all seems to work fine!
Thank you
Jacques

Le ven. 5 avr. 2019 13:07, Floessie notifications@github.com a écrit :

@Desmis https://github.com/Desmis

But what I miss when you post a patch, what to do exactly ?
For me no differences with and whithout, if I speak behavior "locallab"

Then everything is fine.

I was asked
https://github.com/Beep6581/RawTherapee/issues/5261#issuecomment-480005693
by @heckflosse https://github.com/heckflosse to take a look at the
memory behavior, found a big bunch of leaks in the new code and posted a
patch to fix them. There should be no functional difference. If I don't
write what to test exactly I assume you check if it still works the way you
expect it. That's what you did, so all is fine. 👍


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/Beep6581/RawTherapee/issues/5261#issuecomment-480236920,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ANIIWdeIwSGMwK1wTp9LvGBXMuozY3uKks5vdy6JgaJpZM4caq1q
.

@Floessie @heckflosse @Desmis
I conducted some tests from the "plumbing" branch. What I found is that apparently the main leaks I observe probably come from the wavelet levels. Here's the state of memory usage (in GB) after each step:

  | locallab (12 active spots) | wavelet | locallab + wavelet
-- | -- | -- | --
load RT | 0.24 | 0.24 | 0.23
open image in editor | 0.76 | 0.78 | 0.76
zoom in/out (z / alt+f) 20 times | 1.05 | 1.16 | 1.07
Save 20 times (ctr+s) | 1.14 | 1.76 | 1.93
Save 20 times (queue) | 1.14 | 1.82 | 1.99

@sguyader Sébastien, can you please provide the pp3 you used for your wavelet test?

Strange... I don't get the same results everytime:

  | neutral | locallab (12 spots) | wavelet | locallab+wavelet
-- | -- | -- | -- | --
load RT | 0.24 | 0.24 | 0.24 | 0.24
open image in editor | 0.73 | 0.73 | 0.72 | 0.73
zoom in/out (z / alt+f) 20 times | 0.79 | 0.93 | 0.82 | 0.79
Save 20 times (ctr+s) | 0.94 | 1.04 | 0.99 | 1.57
Save 20 times (queue) | 0.94 | 1.15 | 1.09 | 1.75

This time wavelet alone does nothing strange, but associated with locallab it does.
Notice that I close and restart RT between every test run.

@sguyader Sébastien, can you please provide the pp3 you used for your wavelet test?

@heckflosse here's the pp3:

DSCF7842.RAF.pp3.txt

@sguyader To separate real leaks from unfavorable malloc() patterns, please start RT with MALLOC_ARENA_MAX=1 or MALLOC_MMAP_THRESHOLD_=4096 as proposed in #4416.

@Floessie thanks for the tip. I started RT with MALLOC_ARENA_MAX=1 and memory usage now stays constant:

  | neutral | locallab+wavelet
-- | -- | --
load RT | 0.21 | 0.25
open image in editor | 0.71 | 0.72
zoom in/out (z / alt+f) 20 times | 0.73 | 0.75
Save 20 times (ctr+s) | 0.73 | 0.75

Slightly less memory used with MALLOC_MMAP_THRESHOLD_=4096:

  | neutral | locallab+wavelet
-- | -- | --
load RT | 0.2 | 0.2
open image in editor | 0.71 | 0.71
zoom in/out (z / alt+f) 20 times | 0.72 | 0.72
Save 20 times (ctr+s) | 0.73 | 0.73

So we're not hunting big leaks here. There are still some little ones here and there which could make larger areas sticky in glib's malloc().

Just my 2¢,
Flössie

As a user, is it okay to run RT with MALLOC_MMAP_THRESHOLD_=4096 for day-to-day use?

@Floessie @Pandagrapher @heckflosse @sguyader

I push a branch "newlocallab_flo_memleak"
This branch contains the "big" patch (with the time, I change manually current code"...big job!... I hope no error ...) and the last 152d8c3

By cons, It does not take into account the crash in "blur" when the spot is outside the preview

jacques

Closing for now, since there have been plenty of changes to the locallab code and it is now merged into dev.
@sguyader If you ever find a (presumed) leak again, please open a new issue.

Was this page helpful?
0 / 5 - 0 ratings