From c137e70f72430d552dcf20037a7fa444329cc642 Mon Sep 17 00:00:00 2001
From: Giovanni Bussi <giovanni.bussi@gmail.com>
Date: Wed, 18 Apr 2018 16:21:07 +0200
Subject: [PATCH] vesselRegister().create() now returns a unique_ptr

Notice that this change required a bit of hacking.
setAveragingAction now takes a std::unique_ptr as an argument.

I think ownership is clearer now since it is explicitly declared.
---
 src/adjmat/AdjacencyMatrixBase.cpp     |  4 +++-
 src/analysis/Average.cpp               |  4 +++-
 src/analysis/Histogram.cpp             |  7 ++++---
 src/gridtools/ActionWithGrid.cpp       | 11 +++++++----
 src/gridtools/ActionWithGrid.h         |  6 ++++--
 src/gridtools/ConvertToFES.cpp         |  8 ++++----
 src/gridtools/FindContourSurface.cpp   |  4 ++--
 src/gridtools/FindSphericalContour.cpp |  6 ++++--
 src/gridtools/FourierTransform.cpp     |  6 +++---
 src/gridtools/InterpolateGrid.cpp      |  7 ++++---
 src/multicolvar/MultiColvarDensity.cpp |  8 +++++---
 src/vesselbase/ActionWithAveraging.cpp |  5 +++--
 src/vesselbase/ActionWithAveraging.h   |  2 +-
 src/vesselbase/ActionWithVessel.cpp    | 15 ++++++---------
 src/vesselbase/ActionWithVessel.h      |  2 +-
 src/vesselbase/VesselRegister.cpp      |  5 ++---
 src/vesselbase/VesselRegister.h        |  7 ++++---
 17 files changed, 60 insertions(+), 47 deletions(-)

diff --git a/src/adjmat/AdjacencyMatrixBase.cpp b/src/adjmat/AdjacencyMatrixBase.cpp
index 457b08791..cae178b0a 100644
--- a/src/adjmat/AdjacencyMatrixBase.cpp
+++ b/src/adjmat/AdjacencyMatrixBase.cpp
@@ -161,7 +161,9 @@ void AdjacencyMatrixBase::finishMatrixSetup( const bool& symmetric, const std::v
 
   vesselbase::VesselOptions da("","",0,param,this);
   Keywords keys; AdjacencyMatrixVessel::registerKeywords( keys );
-  vesselbase::VesselOptions da2(da,keys); mat = new AdjacencyMatrixVessel(da2); addVessel( mat );
+  vesselbase::VesselOptions da2(da,keys);
+  std::unique_ptr<AdjacencyMatrixVessel> ves( new AdjacencyMatrixVessel(da2) );
+  addVessel( std::move( ves ) );
   setupMultiColvarBase( all_atoms );
 }
 
diff --git a/src/analysis/Average.cpp b/src/analysis/Average.cpp
index e2e61b2f9..7faa57102 100644
--- a/src/analysis/Average.cpp
+++ b/src/analysis/Average.cpp
@@ -127,7 +127,9 @@ Average::Average( const ActionOptions& ao ):
   vesselbase::VesselOptions da("myaverage","",-1,instring,this);
   Keywords keys; AverageVessel::registerKeywords( keys );
   vesselbase::VesselOptions dar( da, keys );
-  myaverage = new AverageVessel(dar); setAveragingAction( myaverage, false );
+  std::unique_ptr<AverageVessel> average( new AverageVessel(dar) );
+  myaverage = average.get();
+  setAveragingAction( std::move(average), false );
 }
 
 void Average::performOperations( const bool& from_update ) {
diff --git a/src/analysis/Histogram.cpp b/src/analysis/Histogram.cpp
index 705e7f606..0da49d077 100644
--- a/src/analysis/Histogram.cpp
+++ b/src/analysis/Histogram.cpp
@@ -312,7 +312,8 @@ Histogram::Histogram(const ActionOptions&ao):
     }
   }
   // And create the grid
-  createGrid( "histogram", vstring );
+  auto grid=createGrid( "histogram", vstring );
+  // notice that createGrid also sets mygrid=grid.get()
   if( mygrid->getType()=="flat" ) {
     if( mvectors ) error("computing histogram for three dimensional vectors but grid is not of fibonacci type - use CONCENTRATION");
     std::vector<std::string> gmin( narg ), gmax( narg );
@@ -333,12 +334,12 @@ Histogram::Histogram(const ActionOptions&ao):
   if( myvessels.size()>0 ) {
     // Create a task list
     for(unsigned i=0; i<myvessels[0]->getFullNumberOfTasks(); ++i) addTaskToList(i);
-    setAveragingAction( mygrid, true );
+    setAveragingAction( std::move(grid), true );
   } else {
     // Create a task list
     for(unsigned i=0; i<mygrid->getNumberOfPoints(); ++i) addTaskToList(i);
     myhist->addOneKernelEachTimeOnly();
-    setAveragingAction( mygrid, myhist->noDiscreteKernels() );
+    setAveragingAction( std::move(grid), myhist->noDiscreteKernels() );
   }
   checkRead();
 }
diff --git a/src/gridtools/ActionWithGrid.cpp b/src/gridtools/ActionWithGrid.cpp
index 44d51dbcb..0b3011c51 100644
--- a/src/gridtools/ActionWithGrid.cpp
+++ b/src/gridtools/ActionWithGrid.cpp
@@ -41,7 +41,7 @@ ActionWithGrid::ActionWithGrid( const ActionOptions& ao):
 {
 }
 
-void ActionWithGrid::createGrid( const std::string& type, const std::string& inputstr ) {
+std::unique_ptr<GridVessel> ActionWithGrid::createGrid( const std::string& type, const std::string& inputstr ) {
   // Start creating the input for the grid
   std::string vstring = inputstr;
   if( keywords.exists("KERNEL") ) {
@@ -57,15 +57,18 @@ void ActionWithGrid::createGrid( const std::string& type, const std::string& inp
   vesselbase::VesselOptions da("mygrid","",-1,vstring,this);
   Keywords keys; gridtools::AverageOnGrid::registerKeywords( keys );
   vesselbase::VesselOptions dar( da, keys );
+  std::unique_ptr<GridVessel> grid;
   if( type=="histogram" ) {
-    mygrid = new HistogramOnGrid(dar);
+    grid.reset( new HistogramOnGrid(dar) );
   } else if( type=="average" ) {
-    mygrid = new AverageOnGrid(dar);
+    grid.reset( new AverageOnGrid(dar) );
   } else if( type=="grid" ) {
-    mygrid = new GridVessel(dar);
+    grid.reset( new GridVessel(dar) );
   } else {
     plumed_merror("no way to create grid of type " + type );
   }
+  mygrid=grid.get();
+  return grid;
 }
 
 void ActionWithGrid::turnOnDerivatives() {
diff --git a/src/gridtools/ActionWithGrid.h b/src/gridtools/ActionWithGrid.h
index 86e676a59..cfa5da327 100644
--- a/src/gridtools/ActionWithGrid.h
+++ b/src/gridtools/ActionWithGrid.h
@@ -39,8 +39,10 @@ private:
 protected:
 /// The grid vessel
   GridVessel* mygrid;
-/// Read in stuff that is specifically for the grid and create it
-  void createGrid( const std::string& type, const std::string& inputstr );
+/// Read in stuff that is specifically for the grid and create it.
+/// Notice that this not only returns a unique_ptr but also set the protected
+/// member mygrid as an alias to that unique_ptr.
+  std::unique_ptr<GridVessel> createGrid( const std::string& type, const std::string& inputstr );
 public:
   static void registerKeywords( Keywords& keys );
   explicit ActionWithGrid( const ActionOptions& );
diff --git a/src/gridtools/ConvertToFES.cpp b/src/gridtools/ConvertToFES.cpp
index 989e5e4f0..0eac068c0 100644
--- a/src/gridtools/ConvertToFES.cpp
+++ b/src/gridtools/ConvertToFES.cpp
@@ -92,11 +92,11 @@ ConvertToFES::ConvertToFES(const ActionOptions&ao):
   plumed_assert( ingrid->getNumberOfComponents()==1 );
 
   // Create a grid
-  createGrid( "grid", "COMPONENTS=" + getLabel() + " " + ingrid->getInputString() );
-  if( ingrid->noDerivatives() ) mygrid->setNoDerivatives();
+  auto grid=createGrid( "grid", "COMPONENTS=" + getLabel() + " " + ingrid->getInputString() );
+  if( ingrid->noDerivatives() ) grid->setNoDerivatives();
   std::vector<double> fspacing;
-  mygrid->setBounds( ingrid->getMin(), ingrid->getMax(), ingrid->getNbin(), fspacing);
-  setAveragingAction( mygrid, true );
+  grid->setBounds( ingrid->getMin(), ingrid->getMax(), ingrid->getNbin(), fspacing);
+  setAveragingAction( std::move(grid), true );
 
   simtemp=0.; parse("TEMP",simtemp);
   if(simtemp>0) simtemp*=plumed.getAtoms().getKBoltzmann();
diff --git a/src/gridtools/FindContourSurface.cpp b/src/gridtools/FindContourSurface.cpp
index cce85179b..075c292c3 100644
--- a/src/gridtools/FindContourSurface.cpp
+++ b/src/gridtools/FindContourSurface.cpp
@@ -144,8 +144,8 @@ FindContourSurface::FindContourSurface(const ActionOptions&ao):
   for(unsigned i=1; i<gdirs.size(); ++i) {
     if( ingrid->isPeriodic(gdirs[i]) ) vstring+=",T"; else vstring+=",F";
   }
-  createGrid( "grid", vstring ); mygrid->setNoDerivatives();
-  setAveragingAction( mygrid, true );
+  auto grid=createGrid( "grid", vstring ); grid->setNoDerivatives();
+  setAveragingAction( std::move(grid), true );
 }
 
 void FindContourSurface::clearAverage() {
diff --git a/src/gridtools/FindSphericalContour.cpp b/src/gridtools/FindSphericalContour.cpp
index 72e256b98..e57d2fce0 100644
--- a/src/gridtools/FindSphericalContour.cpp
+++ b/src/gridtools/FindSphericalContour.cpp
@@ -140,8 +140,10 @@ FindSphericalContour::FindSphericalContour(const ActionOptions&ao):
   log.printf("  looking for contour in windows of length %f \n", (max-min)/nbins);
   // Set this here so the same set of grid points are used on every turn
   std::string vstring = "TYPE=fibonacci COMPONENTS=" + getLabel() + " COORDINATES=x,y,z PBC=F,F,F";
-  createGrid( "grid", vstring ); mygrid->setNoDerivatives();
-  setAveragingAction( mygrid, true ); mygrid->setupFibonacciGrid( npoints );
+  auto grid=createGrid( "grid", vstring ); grid->setNoDerivatives();
+  setAveragingAction( std::move(grid), true );
+  // use mygrid, since at this point grid has been moved
+  mygrid->setupFibonacciGrid( npoints );
 
   checkRead();
   // Create a task list
diff --git a/src/gridtools/FourierTransform.cpp b/src/gridtools/FourierTransform.cpp
index 05f4d9724..b3d151005 100644
--- a/src/gridtools/FourierTransform.cpp
+++ b/src/gridtools/FourierTransform.cpp
@@ -163,9 +163,9 @@ FourierTransform::FourierTransform(const ActionOptions&ao):
 
 
   // Create a grid on which to store the fourier transform of the input grid
-  createGrid( "grid", vstring );
-  if( ingrid->noDerivatives() ) mygrid->setNoDerivatives();
-  setAveragingAction( mygrid, false );
+  auto grid=createGrid( "grid", vstring );
+  if( ingrid->noDerivatives() ) grid->setNoDerivatives();
+  setAveragingAction( std::move(grid), false );
 
   checkRead();
 #endif
diff --git a/src/gridtools/InterpolateGrid.cpp b/src/gridtools/InterpolateGrid.cpp
index fc1d98c1d..70fcf48ed 100644
--- a/src/gridtools/InterpolateGrid.cpp
+++ b/src/gridtools/InterpolateGrid.cpp
@@ -76,7 +76,8 @@ InterpolateGrid::InterpolateGrid(const ActionOptions&ao):
   plumed_assert( ingrid->getNumberOfComponents()==1 );
   if( ingrid->noDerivatives() ) error("cannot interpolate a grid that does not have derivatives");
   // Create the input from the old string
-  createGrid( "grid", "COMPONENTS=" + getLabel() + " " + ingrid->getInputString()  );
+  auto grid=createGrid( "grid", "COMPONENTS=" + getLabel() + " " + ingrid->getInputString()  );
+  // notice that createGrid also sets mygrid=grid.get()
 
   std::vector<unsigned> nbin; parseVector("GRID_BIN",nbin);
   std::vector<double> gspacing; parseVector("GRID_SPACING",gspacing);
@@ -85,8 +86,8 @@ InterpolateGrid::InterpolateGrid(const ActionOptions&ao):
   }
 
   // Need this for creation of tasks
-  mygrid->setBounds( ingrid->getMin(), ingrid->getMax(), nbin, gspacing );
-  setAveragingAction( mygrid, true );
+  grid->setBounds( ingrid->getMin(), ingrid->getMax(), nbin, gspacing );
+  setAveragingAction( std::move(grid), true );
 
   // Now create task list
   for(unsigned i=0; i<mygrid->getNumberOfPoints(); ++i) addTaskToList(i);
diff --git a/src/multicolvar/MultiColvarDensity.cpp b/src/multicolvar/MultiColvarDensity.cpp
index b2941aa57..b44779881 100644
--- a/src/multicolvar/MultiColvarDensity.cpp
+++ b/src/multicolvar/MultiColvarDensity.cpp
@@ -228,10 +228,12 @@ MultiColvarDensity::MultiColvarDensity(const ActionOptions&ao):
   // Create a task list
   for(unsigned i=0; i<mycolv->getFullNumberOfTasks(); ++i) addTaskToList(i);
   // And create the grid
-  if( mycolv->isDensity() ) createGrid( "histogram", vstring );
-  else createGrid( "average", vstring );
+  std::unique_ptr<gridtools::GridVessel> grid;
+  if( mycolv->isDensity() ) grid=createGrid( "histogram", vstring );
+  else grid=createGrid( "average", vstring );
+  mygrid=grid.get();
   // And finish the grid setup
-  setAveragingAction( mygrid, true );
+  setAveragingAction( std::move(grid), true );
 
   // Enusre units for cube files are set correctly
   if( !fractional ) {
diff --git a/src/vesselbase/ActionWithAveraging.cpp b/src/vesselbase/ActionWithAveraging.cpp
index 2ff6bd190..a0ddedad3 100644
--- a/src/vesselbase/ActionWithAveraging.cpp
+++ b/src/vesselbase/ActionWithAveraging.cpp
@@ -81,8 +81,9 @@ ActionWithAveraging::ActionWithAveraging( const ActionOptions& ao ):
   }
 }
 
-void ActionWithAveraging::setAveragingAction( AveragingVessel* av_vessel, const bool& usetasks ) {
-  myaverage=av_vessel; addVessel( myaverage );
+void ActionWithAveraging::setAveragingAction( std::unique_ptr<AveragingVessel> av_vessel, const bool& usetasks ) {
+  myaverage=av_vessel.get();
+  addVessel( std::move(av_vessel) );
   useRunAllTasks=usetasks; resizeFunctions();
 }
 
diff --git a/src/vesselbase/ActionWithAveraging.h b/src/vesselbase/ActionWithAveraging.h
index 45ded46bc..7d482399c 100644
--- a/src/vesselbase/ActionWithAveraging.h
+++ b/src/vesselbase/ActionWithAveraging.h
@@ -65,7 +65,7 @@ protected:
 /// The current weight and its logarithm
   double lweight, cweight;
 /// Set the averaging action
-  void setAveragingAction( AveragingVessel* av_vessel, const bool& usetasks );
+  void setAveragingAction( std::unique_ptr<AveragingVessel> av_vessel, const bool& usetasks );
 /// Check if we are using the normalization condition when calculating this quantity
   bool noNormalization() const ;
 public:
diff --git a/src/vesselbase/ActionWithVessel.cpp b/src/vesselbase/ActionWithVessel.cpp
index 3a8a66c1f..31d41772d 100644
--- a/src/vesselbase/ActionWithVessel.cpp
+++ b/src/vesselbase/ActionWithVessel.cpp
@@ -99,19 +99,16 @@ ActionWithVessel::~ActionWithVessel() {
 
 void ActionWithVessel::addVessel( const std::string& name, const std::string& input, const int numlab ) {
   VesselOptions da(name,"",numlab,input,this);
-  Vessel* vv=vesselRegister().create(name,da);
-  FunctionVessel* fv=dynamic_cast<FunctionVessel*>(vv);
+  std::unique_ptr<Vessel> vv=vesselRegister().create(name,da);
+  FunctionVessel* fv=dynamic_cast<FunctionVessel*>(vv.get());
   if( fv ) {
     std::string mylabel=Vessel::transformName( name );
     plumed_massert( keywords.outputComponentExists(mylabel,false), "a description of the value calculated by vessel " + name + " has not been added to the manual");
   }
-  addVessel(vv);
+  addVessel(std::move(vv));
 }
 
-void ActionWithVessel::addVessel( Vessel* vv ) {
-// logically, this function should accept a unique_ptr.
-// temporarily, we make here the conversion:
-  std::unique_ptr<Vessel> vv_ptr(vv);
+void ActionWithVessel::addVessel( std::unique_ptr<Vessel> vv_ptr ) {
 
 // In the original code, the dynamically casted pointer was deleted here.
 // Now that vv_ptr is a unique_ptr, the object will be deleted automatically when
@@ -150,9 +147,9 @@ StoreDataVessel* ActionWithVessel::buildDataStashes( ActionWithVessel* actionTha
   }
 
   VesselOptions da("","",0,"",this);
-  StoreDataVessel* mm=new StoreDataVessel(da);
+  std::unique_ptr<StoreDataVessel> mm( new StoreDataVessel(da) );
   if( actionThatUses ) mm->addActionThatUses( actionThatUses );
-  addVessel(mm);
+  addVessel(std::move(mm));
 
   // Make sure resizing of vessels is done
   resizeFunctions();
diff --git a/src/vesselbase/ActionWithVessel.h b/src/vesselbase/ActionWithVessel.h
index f6db97bbb..d4e454d22 100644
--- a/src/vesselbase/ActionWithVessel.h
+++ b/src/vesselbase/ActionWithVessel.h
@@ -107,7 +107,7 @@ protected:
   std::vector<unsigned> taskFlags;
 /// Add a vessel to the list of vessels
   void addVessel( const std::string& name, const std::string& input, const int numlab=0 );
-  void addVessel( Vessel* vv );
+  void addVessel( std::unique_ptr<Vessel> vv );
 /// Add a bridging vessel to the list of vessels
   BridgeVessel* addBridgingVessel( ActionWithVessel* tome );
 /// Complete the setup of this object (this routine must be called after construction of ActionWithValue)
diff --git a/src/vesselbase/VesselRegister.cpp b/src/vesselbase/VesselRegister.cpp
index d8afaf2da..c9329847e 100644
--- a/src/vesselbase/VesselRegister.cpp
+++ b/src/vesselbase/VesselRegister.cpp
@@ -62,14 +62,13 @@ bool VesselRegister::check(std::string key) {
   return false;
 }
 
-Vessel* VesselRegister::create(std::string keyword, const VesselOptions&da) {
-  Vessel* df;
+std::unique_ptr<Vessel> VesselRegister::create(std::string keyword, const VesselOptions&da) {
+  std::unique_ptr<Vessel> df;
   if(check(keyword)) {
     Keywords keys; mk[keyword](keys);
     VesselOptions nda( da,keys );
     df=m[keyword](nda);
   }
-  else df=NULL;
   return df;
 }
 
diff --git a/src/vesselbase/VesselRegister.h b/src/vesselbase/VesselRegister.h
index b589f7936..ccb14c97e 100644
--- a/src/vesselbase/VesselRegister.h
+++ b/src/vesselbase/VesselRegister.h
@@ -26,6 +26,7 @@
 #include <cstring>
 #include <vector>
 #include <map>
+#include <memory>
 #include "tools/Exception.h"
 #include "tools/Keywords.h"
 
@@ -38,7 +39,7 @@ class VesselOptions;
 class VesselRegister {
 private:
 /// Pointer to a function which, given the keyword for a distribution function, creates it
-  typedef Vessel*(*creator_pointer)(const VesselOptions&);
+  typedef std::unique_ptr<Vessel>(*creator_pointer)(const VesselOptions&);
 /// Pointer to the function that reserves the keyword for the distribution
   typedef void(*keyword_pointer)(Keywords&);
 /// The set of possible distribution functions we can work with
@@ -57,7 +58,7 @@ public:
 /// Verify if a distribution keyword is present in the register
   bool check(std::string keyname);
 /// Create a distribution function of the specified type
-  Vessel* create(std::string keyword, const VesselOptions&da);
+  std::unique_ptr<Vessel> create(std::string keyword, const VesselOptions&da);
 /// Return the keywords
   Keywords getKeywords();
 };
@@ -66,7 +67,7 @@ VesselRegister& vesselRegister();
 
 #define PLUMED_REGISTER_VESSEL(classname,keyword) \
   static class classname##RegisterMe{ \
-    static PLMD::vesselbase::Vessel * create(const PLMD::vesselbase::VesselOptions&da){return new classname(da);} \
+    static std::unique_ptr<PLMD::vesselbase::Vessel> create(const PLMD::vesselbase::VesselOptions&da){return std::unique_ptr<classname>( new classname(da) );} \
   public: \
     classname##RegisterMe(){PLMD::vesselbase::vesselRegister().add(keyword,create,classname::reserveKeyword,classname::registerKeywords);} \
     ~classname##RegisterMe(){PLMD::vesselbase::vesselRegister().remove(create);} \
-- 
GitLab