Use a copyable unique pointer

Use a copyable unique pointer instead of writing custom copy constructor
and assignment operator.
This commit is contained in:
Håkon Hægland 2022-09-19 01:42:09 +02:00
parent 38add2ed66
commit d15c5b51c8

View File

@ -122,7 +122,9 @@ class BlackOilIntensiveQuantities
struct DirectionalMobility { struct DirectionalMobility {
using array_type = std::array<Evaluation,numPhases>; using array_type = std::array<Evaluation,numPhases>;
DirectionalMobility(const array_type& mX, const array_type& mY, const array_type& mZ) DirectionalMobility(const DirectionalMobility& other)
: mobilityX_{other.mobilityX_}, mobilityY_{other.mobilityY_}, mobilityZ_{other.mobilityZ_} {}
DirectionalMobility(const array_type& mX, const array_type& mY, const array_type& mZ)
: mobilityX_{mX}, mobilityY_{mY}, mobilityZ_{mZ} {} : mobilityX_{mX}, mobilityY_{mY}, mobilityZ_{mZ} {}
DirectionalMobility() : mobilityX_{}, mobilityY_{}, mobilityZ_{} {} DirectionalMobility() : mobilityX_{}, mobilityY_{}, mobilityZ_{} {}
array_type& getArray(int index) { array_type& getArray(int index) {
@ -142,6 +144,59 @@ class BlackOilIntensiveQuantities
array_type mobilityZ_; array_type mobilityZ_;
}; };
// Instead of writing a custom copy constructor and a custom assignment operator just to handle
// the dirMob_ unique ptr member variable when copying BlackOilIntensiveQuantites (see for example
// updateIntensitiveQuantities_() in fvbaseelementcontext.hh for a copy example) we write the below
// custom wrapper class CopyablePtr which wraps the unique ptr and makes it copyable.
//
// The advantage of this approach is that we avoid having to call all the base class copy constructors and
// assignment operators explicitly (which is needed when writing the custom copy constructor and assignment
// operators) which could become maintenance burden. For example, when adding a new base class (if that should
// be needed sometime in the future) to BlackOilIntensiveQuantites we could forget to update the copy
// constructor and assignment operators.
//
// We want each copy of the BlackOilIntensiveQuantites to be unique, (TODO: why?) so we have to make a copy
// of the unique_ptr each time we copy construct or assign to it from another BlackOilIntensiveQuantites.
// (On the other hand, if a copy could share the ptr with the original, a shared_ptr could be used instead and the
// wrapper would not be needed)
template <class T>
class CopyablePtr {
public:
CopyablePtr() : ptr_(nullptr) {}
CopyablePtr(const CopyablePtr& other) {
if (other) { // other does not contain a nullptr
ptr_ = std::make_unique<T>(other.get());
}
// else {ptr_ = nullptr;} // this is the default construction value
}
// assignment operator
CopyablePtr<T>& operator=(const CopyablePtr<T>& other) {
if (other) {
ptr_ = std::make_unique<T>(other.get());
}
else {
ptr_ = nullptr;
}
return *this;
}
// assign directly from a unique_ptr
CopyablePtr<T>& operator=(std::unique_ptr<T>&& uptr) {
ptr_ = std::move(uptr);
return *this;
}
// member access operator
T* operator->() const {return ptr_.get(); }
// boolean context operator
explicit operator bool() const noexcept {
return ptr_ ? true : false;
}
// get a reference to the stored value
T& get() const {return *ptr_;}
T* release() const {return ptr_.release();}
private:
std::unique_ptr<T> ptr_;
};
public: public:
using FluidState = BlackOilFluidState<Evaluation, using FluidState = BlackOilFluidState<Evaluation,
FluidSystem, FluidSystem,
@ -161,47 +216,9 @@ public:
fluidState_.setRv(0.0); fluidState_.setRv(0.0);
} }
} }
BlackOilIntensiveQuantities(const BlackOilIntensiveQuantities& other) = default;
BlackOilIntensiveQuantities(const BlackOilIntensiveQuantities& other) { BlackOilIntensiveQuantities& operator=(const BlackOilIntensiveQuantities& other) = default;
if (other.dirMob_) {
dirMob_ = std::make_unique<DirectionalMobility>(
other.dirMob_->mobilityX_,
other.dirMob_->mobilityY_,
other.dirMob_->mobilityY_
);
}
};
BlackOilIntensiveQuantities& operator=(const BlackOilIntensiveQuantities& other) {
fluidState_ = other.fluidState_;
referencePorosity_ = other.referencePorosity_;
porosity_ = other.porosity_;
rockCompTransMultiplier_ = other.rockCompTransMultiplier_;
mobility_ = other.mobility_;
if (other.dirMob_) {
dirMob_ = std::make_unique<DirectionalMobility>(
other.dirMob_->mobilityX_,
other.dirMob_->mobilityY_,
other.dirMob_->mobilityY_
);
}
else {
dirMob_.release(); // release any memory, and assign nullptr
}
// call assignment operators in the parent classes
GetPropType<TypeTag, Properties::DiscIntensiveQuantities>::operator=(other);
GetPropType<TypeTag, Properties::FluxModule>::FluxIntensiveQuantities::operator=(other);
BlackOilDiffusionIntensiveQuantities<TypeTag, getPropValue<TypeTag, Properties::EnableDiffusion>() >::operator=(other);
BlackOilSolventIntensiveQuantities<TypeTag>::operator=(other);
BlackOilExtboIntensiveQuantities<TypeTag>::operator=(other);
BlackOilPolymerIntensiveQuantities<TypeTag>::operator=(other);
BlackOilFoamIntensiveQuantities<TypeTag>::operator=(other);
BlackOilBrineIntensiveQuantities<TypeTag>::operator=(other);
BlackOilEnergyIntensiveQuantities<TypeTag>::operator=(other);
BlackOilMICPIntensiveQuantities<TypeTag>::operator=(other);
return *this;
};
/*! /*!
* \copydoc IntensiveQuantities::update * \copydoc IntensiveQuantities::update
@ -685,7 +702,7 @@ private:
static void updateRelperms( static void updateRelperms(
std::array<Evaluation,numPhases> &mobility, std::array<Evaluation,numPhases> &mobility,
std::unique_ptr<DirectionalMobility> &dirMob, CopyablePtr<DirectionalMobility> &dirMob,
FluidState &fluidState, FluidState &fluidState,
const Problem& problem, const Problem& problem,
const MaterialLawParams& materialParams, const MaterialLawParams& materialParams,
@ -731,7 +748,7 @@ private:
Evaluation porosity_; Evaluation porosity_;
Evaluation rockCompTransMultiplier_; Evaluation rockCompTransMultiplier_;
std::array<Evaluation,numPhases> mobility_; std::array<Evaluation,numPhases> mobility_;
std::unique_ptr<DirectionalMobility> dirMob_; CopyablePtr<DirectionalMobility> dirMob_;
}; };
} // namespace Opm } // namespace Opm