Recently I asked following question:
Best method to implement an abstract factory pattern
My future research show that you can implement the factory like this:
#include <stdio.h>
#include <memory>
class Base{
char x[20000];
};
class Child : public Base{
public:
Child(int a, int b){
}
};
std::unique_ptr<Base> factory(){
return std::unique_ptr<Base> { new Child(5, 6) };
}
int main(){
Base & a = *factory();
return 0;
}
This compiles without warnings, and it make no memory leak, even std::unique_ptr is dereferenced immediately.
Is this Base & a = *factory(); legitimate and well accepted way to "collect" value from factory?
The only problem I see here would be if a variable leave the scope. Is there something I am missing here?
Base &a = *factory();
You dereferenced the unique_ptr and kept the reference to its pointee.
But you didn't store the unique_ptr itself.
Thus it dies at the end of the statement, taking its pointee with it, and your reference is now dangling.
Related
I would like to use the "Strategy" design pattern, and have just one simple question.
We have two classes: Base as an abstract class and Derived as a concrete class.
#include <iostream>
using namespace std;
class Base {
public:
virtual void func() = 0;
};
class Derived : public Base{
public:
virtual void func() override
{
printf("hello \n");
}
};
int main(){
Base * base = new Derived();
base->func();
Derived derived2;
Base & base2 = derived2;
base2.func();
return 0;
}
Using pointer,
Base * base = new Derived();
Using reference
Derived derived2;
Base & base2 = derived2;
Is there any way to write in one line for reference?
Which method are you guys use to implement the "strategy" design pattern,
using pointer or reference?
Because of the reason above, I tend to use pointer... but I would like an answer from experts.
Is there any way to write in one line for reference?
You could use static_cast<Base&>. This produces a reference to the Base portion of your object :
int main() {
Derived derived2;
static_cast<Base&>(derived2).func();
return 0;
}
Which method are you guys use to implement the "strategy" design pattern, using pointer or reference?
You don't usually see references used for this because most of the time you need to store your polymorphic object and that's not practical with references. References refer to an object, but that object needs to otherwise exist somewhere else.
Notice that your first case creates a dynamically allocated instance, you can pass the pointer around easily. The second one creates a local object which is much harder to move around polymorphically. If you try to store your Derived object into a container, you'll certainly need to dynamically allocate it anyway. Trying to do otherwise will result in object slicing (where the derived portion is entirely sliced off).
For example, this is how you would store a Derived into a container of Base pointers :
int main()
{
std::vector<std::unique_ptr<Base>> my_bases;
my_bases.emplace_back(std::make_unique<Derived>());
}
If you tried to use a std::vector<Base> it wouldn't compile (Base is abstract). But even if it did compile (by making Base concrete) it would not behave polymorphically. This is not unique to the strategy pattern. This is how it works whenever you employ polymorphism.
I was using shared_ptr in a project. And at one point I had to store the raw pointers as a void then later convert it back to its shared_ptr form in a callback where the void* was passed. But for some reason the code kept crashing. I didn't understand why since I wasn't getting any compiler errors or warnings. But I noticed that when I was inheriting from std::enable_shared_from_this I wasn't assigning it to be a public inheritance. And that's what was causing the crash.
I wrote an example code and I'm just wondering why it happens.
#include <memory>
#include <iostream>
class TestShared : public std::enable_shared_from_this<TestShared>{
private:
int32_t id;
public:
TestShared(int32_t id){
this->id = id;
}
std::shared_ptr<TestShared> getshared(){
return shared_from_this();
}
int32_t getid(){
return id;
}
};
int main(){
std::shared_ptr<TestShared> ts(new TestShared(0xFF));
void* tsp = ts.get();
std::shared_ptr<TestShared> tsn = ((TestShared*)tsp)->getshared();
std::cout << std::hex << tsn->getid();
return 0;
}
So that code will execute and run fine and I get the expected result.
But when I remove public from the inheritance:
#include <memory>
#include <iostream>
class TestShared : std::enable_shared_from_this<TestShared>{
private:
int32_t id;
public:
TestShared(int32_t id){
this->id = id;
}
std::shared_ptr<TestShared> getshared(){
return shared_from_this();
}
int32_t getid(){
return id;
}
};
int main(){
std::shared_ptr<TestShared> ts(new TestShared(0xFF));
void* tsp = ts.get();
std::shared_ptr<TestShared> tsn = ((TestShared*)tsp)->getshared();
std::cout << std::hex << tsn->getid();
return 0;
}
Then it results in a crash. So why does public make a difference here and why doesn't the compiler give a warning/error?
Being public is important because the shared_ptr system needs to access the enable_shared_from_this base class of the given type. And it can't do that if it's not publicly accessible from the given type.
There is no warning/error for a non-accessible base class because there is no way for the system to know that your code is wrong.
It is conceptually OK to use a shared_ptr constructor that can "enable shared_from_this" even if enable_shared_from_this is private. Why? Consider the following:
class B : public enable_shared_from_this<B> {...};
class D : private B {...};
Now, B expects to be able to do shared_from_this gymnastics. But D privately inherited from it. So D's relationship to B (and thus to B::shared_from_this) is private. Maybe D is using B in such a way that it doesn't trigger any of the shared_from_this usage.
So if D is not relying on B::shared_from_this, if B is just an implementation-detail of D, why is it an error if someone puts a D in a shared_ptr?
There is no test you can come up with which will not give rise to false positives like this. Therefore, if the enable_shared_from_this base class is not accessible, then shared_ptr constructors that could try to use it simply do not attempt to use it.
According to https://en.cppreference.com/w/cpp/memory/enable_shared_from_this
A common implementation for enable_shared_from_this is to hold a weak reference (such as std::weak_ptr) to this. The constructors of std::shared_ptr detect the presence of an unambiguous and accessible (since C++17) enable_shared_from_this base and assign the newly created std::shared_ptr to the internally stored weak reference if not already owned by a live std::shared_ptr (since C++17).
If the inheritance is public, then when ts is initialized, it "records" in the enable_shared_from_this base subobject that it is the owner of the TestShared object. When getshared is later called, the base subobject is consulted, and a new shared_ptr object is created that shares ownership with ts.
If the inheritance is not public, then when ts is initialized, it doesn't "know" that there is an enable_shared_from_this subobject that it needs to write to. Thus, when getshared is called, the enable_shared_from_this subobject doesn't contain any information about who currently owns the object. In C++17, this results in an exception; before C++17, the result is undefined.
I've been looking everywhere on the internet and didn't find any decent answer to following problem.
The code:
class P {
public:
virtual void play() = 0;
};
class A: public P {
public:
void play() { };
};
P myVar= A();
The last line gives following error: cannot allocate an object of abstract type 'Song'
Although, class A overrided the play()-method and I'm allocating an object of class A instead of P, what am I doing wrong here?
The problem is that you are trying to make an object P myVar that slices off the additional implementation in A by copying the object into P.
You cannot do that with "value" objects; you need a pointer or a reference for that. A solution based on built-in C++ pointers looks like this:
P *myPtrVar = new A();
... // Use myPtrVar here
delete myPtrVar;
A solution based on smart pointes looks like this:
std::unique_ptr<P> mySmartPtrVar(new A());
The advantage of using smart pointers is that you do not need to call delete: the object will be deallocated as soon as mySmartPtrVar is out of scope.
And again a bad-formulted question, but I don't know how to shortly explain this situation:
I have two classes. Let's name them A and B. A has a lot of member variables and methods. B is a struct which has a shared_pointer to an object of type A. Now A has a method that returns an instance of B (with a pointer to the current instance of A).
My problem is, that A is the subclass of C. C has the same method as described above as pure virtual. The code would look like this:
class C {
public:
virtual B mymethod() const =0;
virtual int getMyvar() const =0;
};
class A : public C {
public:
B mymethod() const override;
int getMyvar() const override; //outputs myvar
private:
int myvar;
};
struct B {
std::shared_ptr<C> pointer;
};
B A::mymethod() const {
B instance;
instance.pointer = std::make_shared<A>(*this); //is this wrong?
return instance;
}
My compiler (gcc 4.8.2) creates the executables for the following code, but at runtime I get "Segmentation fault (core dumped)":
void AnotherClass::something() const {
A object;
B instance = object.mymethod();
std::cout << instance.pointer->getMyvar(); //dumps the core womehow?
}
I read about the std::enable_shared_from_this but I could not figure out how it works or if it helps me.
Why do I get the error message and how can I fix this?
From what I have read in the manual, you do:
class A : public C, std::enable_shared_from_this<A> {
public:
B mymethod() override; // Notice the lack of const
private:
int myvar;
};
and then:
B A::mymethod() {
B instance;
instance.pointer = shared_from_this(); // this should be right
return instance;
}
Like this, all the instances of a std::shared_ptr to the same A object will share the same reference counter, and it will be destroyed only when it must be.
EDIT:
Also, notice that your object A must be managed by some other std::shared_ptr before you can call A::mymethod(). I.e. you must create A objects like this:
std::shared_ptr<A> a_obj(new A);
then you can call A::mymethod():
B b_obj = a_obj->mymethod();
EDIT2:
Method A::mymethod() (and consequently, C::mymethod()) can't be const to be able to call the non-const method shared_from_this().
Preliminary problem: how do you down-cast to access myvar ?
Edit: after your edit, this first topic is no longer relevant. I leave it because I used this code in the live demos illustrating how to solve it.
First, the statement that causes the dump can't compile as you gave it:
std::cout << instance.pointer->myvar;
because instance.pointer is a shared_ptr<C> and C has no member myvar.
If downcasting properly with dynamic_pointer_cast<A>(instance.pointer)->myvar (supposing AnotherClass is a friend) it works.
Your shared pointer made a clone: is it your intent ?
This statement:
instance.pointer = std::make_shared<A>(*this); //is this wrong? PERHAP'S !?
creates a clone object obtained by copy construction from *this. So you don't reference the original object A, and hence you don't need std::enable_shared_from_this : the use count of instance.pointer will be 1 because at that moment there's only one reference to the newly created shared object.
Live demo
Or do you want it to reference the original object ?
You then have to change the statement to:
instance.pointer = std::shared_ptr<A>(this); //better ?
But this won't compile because mymethod() is const, so it consider this as being a pointer to const. To compile the statement you must either remove the constness of mymethod() or add constness to B's pointer.
Then it works. B's shared pointer has still a use count of 1, which is again ok. But once this shared_ptr gets out of scope, the use count is 0 and the shared_ptr's destructor will try to delete the object. AS IT WAS INITIALY A LOCAL OBJECT (ON STACK) this causes a runtime error.
Final approach
As you want to have shared pointers to your object, the code of AnotherClass should be something like:
shared_ptr<C> pobject(new A); // create the object from the free store
B instance = pobject->mymethod();
...
And the C class must inherit as follows:
class C : public std::enable_shared_from_this<C>
{...}
And the my method class must initialize the shared_pointer it retures as follows:
//instance.pointer = std::shared_ptr<A>(this); // no, don't do no longer !!
instance.pointer = shared_from_this(); //<===== RETURN A POINTER TO SELF
Then everything works perfectly.
Live demo
It seems to me that you would get a memory error when your objects go out of scope.
When you create your object A and then create your shared_ptr with the this pointer, your counter will be 1 instead of 2 (as you would maybe expect). So A will be destroyed twice, instead of once.
A more correct way of doing this would be create class A as a shared_ptr and initialize the pointer in class B with it (not inside class A). This way the counter will be incremented as you expect and A will be deleted only once.
The class you want to share will need to inherit from enable_share_from_this.
Then you can call share_from_this to obtain a shared pointer to the class you're in.
If you just try and make_shared you just create a separate ownership group that will mean two things will try and delete your object. That will be the cause of your segfault.
I have a base class which I am passing with unique_ptr as a reference to a function and I want to copy/move it to a derived class shared_ptr (or unique_ptr what I want it is too guarantee no memory leaked throughout the execution).
I am doing this:
std::shared_ptr<Derived> f(unique_ptr<Base>& b_ptr){
std::shared_ptr<Derived> d_ptr= std::make_shared<Base>(std::move(b_ptr));
return d_ptr;
}
This is what I would like to have, but I know that this is not the right way, I would like to know how could I do something like this.
You are almost correct.
std::make_shared always creates a new object, using perfect forwarding, so unless there is a constructor taking a std::unique_ptr&, thats not what you want.
In order to do this, all you need is the std::shared_ptr's constructor from a std::unique_ptr then use the std::static_pointer_cast function:
#include <memory>
#include <iostream>
class Parent{ virtual ~Parent(); };
class Derived : public Parent { };
std::shared_ptr<Derived> f(std::unique_ptr<Parent>&& b_ptr)
{
auto shared_base = std::shared_ptr < Parent > {std::move(b_ptr)};
return std::static_pointer_cast<Derived>(shared_base);
}
Also, i found it a good idea to pass b_ptr by rvalue-ref because that way the user has the explcitly use std::move(...) on their object just to illustrate that they won't have ownership over the unique_ptr anymore.