I have the following code:
class Cohomology;
struct EMField
{
std::shared_ptr<Cohomology> coh;
std::array<DIM> data;
// other methods
}
class Cohomology
{
private:
// private members
public:
Cohomology(PList params)
{
// Constructor of the class
}
virtual ~Cohomology() {std::cout << "Cohomology destroyed" << std::endl;}
void initializeField(EMField& field)
{
field.coh.reset(this);
// other methods to initialize field.data using the private members
}
}
But the class Cohomology
also has virtual methods that are implemented by SubCohomology
:
class SubCohomology : public Cohomology
{
public:
SubCohomology(PList params) {}
~Cohomology() {std::cout << "SubCohomology destroyed" << std::endl;}
// Implementation of the virtual methods
}
So a test code to check whether EMFields
are initialized and can be manipulated looks like:
int main(int argc, char *argv[])
{
// variables needed to initialize PList params
PList params(); // construct params
SubCohomology coh(params);
EMField field;
coh.initializeField(field);
}
The code compiles, but running it yields this error:
SubCohomology destroyed
Cohomology destroyed
free(): invalid pointer
[machine:324808] *** Process received signal ***
[machine:324808] Signal: Aborted (6)
[machine:324808] Associated errno: Unknown error 32767 (32767)
[machine:324808] Signal code: (24)
[machine:324808] [ 0] /usr/lib/libc.so.6( 0x38a40)[0x7f4ac0054a40]
[machine:324808] [ 1] /usr/lib/libc.so.6( 0x884dc)[0x7f4ac00a44dc]
[machine:324808] [ 2] /usr/lib/libc.so.6(gsignal 0x18)[0x7f4ac0054998]
[machine:324808] [ 3] /usr/lib/libc.so.6(abort 0xd7)[0x7f4ac003e53d]
[machine:324808] [ 4] /usr/lib/libc.so.6( 0x7c67e)[0x7f4ac009867e]
[machine:324808] [ 5] /usr/lib/libc.so.6( 0x9226c)[0x7f4ac00ae26c]
[machine:324808] [ 6] /usr/lib/libc.so.6( 0x940bc)[0x7f4ac00b00bc]
[machine:324808] [ 7] /usr/lib/libc.so.6(__libc_free 0x73)[0x7f4ac00b2a33]
[machine:324808] [ 8] /home/user/builddir/test_fields(_ZN13EMFieldILi0ELi1EED2Ev 0x83)[0x556db1fc0f73]
[machine:324808] [ 9] /home/user/builddir/test_fields(main 0x36e)[0x556db1fa205e]
[machine:324808] [10] /usr/lib/libc.so.6( 0x232d0)[0x7f4ac003f2d0]
[machine:324808] [11] /usr/lib/libc.so.6(__libc_start_main 0x8a)[0x7f4ac003f38a]
[machine:324808] [12] /home/user/builddir/test_fields(_start 0x25)[0x556db1fa3ba5]
[machine:324808] *** End of error message ***
Aborted (core dumped)
which happens after the function initializeField
. It is a memory problem, which might be related to trying to free()
a non-existing resource.
I suspect that using std::enable_shared_from_this might be helpful to address this problem but I don't know how to implement the mandatory inheritance considering my particular problem, as I am trying to initialize the std::shared_ptr<Cohomology> coh
class member of a field in the Cohomology class
.
The example outlined here is very helpful to understand how to use this, but I don't know if I would have to nest another struct in EMField
to implement this. I also understand the problem solved in this question: when should we use std::enable_shared_from_this, but I cannot put it in the context where a struct has a std::shared_ptr
as a member.
Please understand that many EMField
objects might be added, whose std::shared_ptr<Cohomology>
member points for all fields to the same object
Thank you.
CodePudding user response:
std::shared_ptr
exists to manage the lifetime of dynamically-allocated objects. No such management is needed (or possible) for an object with automatic storage duration (like coh
). Its lifetime is tied to its enclosing scope. Therefore a pointer to coh
must never be managed by a std::shared_ptr
.
Instead, you should consider creating a constructor in EMField
that accepts a std::shared_ptr<Cohomology>
and having the caller create an appropriate dynamically-allocated object:
struct EMField
{
std::shared_ptr<Cohomology> coh;
// ...
EMField(std::shared_ptr<Cohomology> c)
: coh{c}
{}
// ...
};
int main(int argc, char *argv[])
{
// variables needed to initialize PList params
PList params(); // construct params
auto coh = std::make_shared<SubCohomology>(params);
EMField field(coh);
// No longer needed since EMField's constructor initializes its
// fields now
// coh.initializeField(field);
}
If you absolutely don't want to have to pass your Cohomology
object into EMField
from the caller, and all Cohomology
objects should be dynamically-allocated, and they should all be managed by std::shared_ptr
s, then, and only then, is std::enable_shared_from_this
the tool for the job.
Example:
class Cohomology : public std::enable_shared_from_this<Cohomology>
{
private:
// private members
protected:
Cohomology(PList params)
{
// Constructor of the class
}
Cohomology(const Cohomology&) = delete;
public:
virtual ~Cohomology()
{
std::cout << "Cohomology destroyed\n";
}
static std::shared_ptr<Cohomology> create(PList params)
{
return std::shared_ptr<Cohomology>(new Cohomology(params));
}
void initializeField(EMField& field)
{
field.coh = shared_from_this();
// ...
}
// ...
};
class SubCohomology : public Cohomology
{
private:
SubCohomology(PList params)
: Cohomology(params)
{}
public:
~SubCohomology()
{
std::cout << "SubCohomology destroyed\n";
}
static std::shared_ptr<SubCohomology> create(PList params)
{
return std::shared_ptr<SubCohomology>(new SubCohomology(params));
}
// Implementation of the virtual methods
};
int main(int argc, char *argv[])
{
// variables needed to initialize PList params
PList params; // construct params
std::shared_ptr<SubCohomology> coh = SubCohomology::create(params);
EMField field;
coh->initializeField(field);
}
Note that Cohomology
and SubCohomology
now have non-public constructors. If you inherit from std::enable_shared_from_this
you should not allow any objects to ever not be managed by a std::shared_ptr
, so separate factory functions are needed to ensure that fact.
CodePudding user response:
- initializeField reset your smart pointer : delete the object
- i think that this method is not in the right object, you may do it outside the Cohomology object