There are a lot of things that needs to be said. First off, I would like to know if the approach below is considered a design pattern or even a common technique (That's why I didnt provide further information on the title). If thats the case, whats the name?
Anyways, this is a minified version of what I'm trying to achieve. Since I need to use copying, I found that using std::shared_ptr is the best to avoid deallocated (deleted) pointers.
class Foo
{
public:
Foo() : ptr(nullptr) {}
Foo(const Foo& foo) : ptr(foo.ptr) {}
virtual ~Foo() = default;
void whatever() {
if (ptr)
ptr->whateverHandler();
}
void reset() {
ptr.reset();
}
void resetBar() {
ptr.reset(new Bar);
}
// Other resets here...
protected:
Foo(Foo* foo) : ptr(foo) {}
private:
// Every child class should override this
virtual void whateverHandler() {
throw "whateverHandler cant be called within base class";
}
protected:
std::shared_ptr<Foo> ptr;
};
class Bar : public Foo
{
public:
Bar() : Foo(this) {}
void whateverHandler() {
printf("Bar's handler!!! \n");
}
};
This all looks good and compiles fine, however, the following exame crashes. Why is that?
int main()
{
{
Foo f;
f.resetBar();
}
return getchar();
}
Bar() : Foo(this) {}
Be careful when you pass this to a shared_ptr.
Think about what will happen afterf.resetBar(); and ptr.reset(new Bar); again.
For new Bar, an object of type Bar will be constructed, and inside its constructor this is passed to the parent class member ptr, then the object is managed by the it which is a std::shared_ptr.
After that, the object is managed by f.ptr; which is another std::shared_ptr.
So there're two std::shared_ptrs pointing to the same object, but std::shared_ptrs don't know anything about that; because you're constructing them separately. When f and f.ptr is destroyed, the pointed-to object will be destroyed too. Then the member ptr will be destroyed, it will try to destroyed the same object again, which leads to UB.
I'm not sure about what the design trying to accomplish, but just stopping passing this to a std::shared_ptr could eliminate UB.
class Foo
{
public:
virtual ~Foo() = default;
void whatever() {
if (ptr)
ptr->whateverHandler();
}
void reset() {
ptr.reset();
}
void resetBar() {
ptr.reset(new Bar);
}
// Other resets here...
private:
// Every child class should override this
virtual void whateverHandler() = 0;
std::shared_ptr<Foo> ptr;
};
class Bar : public Foo
{
public:
void whateverHandler() {
printf("Bar's handler!!! \n");
}
};
int main()
{
{
Foo f;
f.resetBar();
f.whatever();
f.resetSthElse();
f.whatever();
}
}
And IMO, having a member of type std::shared_ptr pointing to derived class is confusing; separating it might be better. And then, I think it might be the bridge design partern.
class Foo
{
public:
void whatever() {
if (ptr)
ptr->whateverHandler();
}
void reset() {
ptr.reset();
}
void resetBar() {
ptr.reset(new BarHandler);
}
// Other resets here...
private:
std::shared_ptr<FooHandler> ptr;
};
class FooHandler
{
public:
virtual ~FooHandler() = default;
// Every child class should override this
virtual void whateverHandler() = 0;
};
class BarHandler : public FooHandler
{
public:
void whateverHandler() {
printf("Bar's handler!!! \n");
}
};
int main()
{
{
Foo f;
f.resetBar();
f.whatever();
f.resetSthElse();
f.whatever();
}
}
The Foo::ptr holds a pointer to its mother Foo(this) with reference count 1.
In Foo::resetBar(), when Foo asking Foo::ptr to call reset(new Bar), Foo::ptr gave up its ownership to its mother Foo(this) and found out the reference count was already decreased to 0, so it need to kill Foo.
When the Foo is dead, its children are killed. So Foo::ptr must be dead, too. Then assigning the new Bar to dead Foo::ptr causes UB.
Related
Is there a way to call a class member function automatically in the end of a scope?
Apparently if the class is instantiated within the same scope, clean() can be used in the destructor of it. The question is, can we achieve that if it is instantiated before the scope? In detail:
class foo
{
public:
void do_something() {}
void clean() {}
};
int main()
{
foo c;
{
c.do_something();
// do something
// call c.clean() automatically
}
}
Something like this. May not be exactly what you are looking for as it requires you do declare another variable at the start of the scope where you want the clean function to be called.
class CleanFoo
{
public:
CleanFoo(Foo& r) : ref(r) {}
~CleanFoo() { ref.clean(); }
CleanFoo(const CleanFoo&) = delete;
CleanFoo& operator=(const CleanFoo&) = delete;
private:
Foo& ref;
};
int main()
{
foo c;
{
CleanFoo cc(c);
...
} // c.clean() will be called here
...
}
std::unique_ptr actually has something like that, in the form of a second parameter you can pass to the constructor, a deleter. The deleter cleans up when the std::unique_ptr object goes out of scope. Normally (i.e. if you don't specify it) it would be std::default_delete that calls delete on the dynamically allocated memory it owns. But you can make it do other things, like this:
#include <cstdio>
#include <memory>
class foo
{
public:
void do_something() { printf("do_something\n"); }
void clean() { printf( "clean\n"); }
};
int main()
{
foo c;
{
std::unique_ptr<foo, void(*)(foo*)> scoped_cleaner(&c, [](foo* c) { c->clean(); });
c.do_something();
}
}
godbolt
Only thing that is called automatically at the end of the scope is the destructors of the objects whose lifetime end in that scope. As such, you could have another object local to the inner scope whose destructor calls the function.
A generic solution exists in Boost already:
foo c;
{
BOOST_SCOPE_EXIT(&c) {
c.clean();
};
c.do_something();
// do something
}
One caveat with all these answers including mine is that foo::clean() must not throw.
Write a do_guard. You can leverage RAII to create a wrapper that will call do on the object you give the wrapper in it's constructor, and then the destructor will call clear. That would look like
struct do_guard
{
foo& ref;
do_guard(foo& ref) : ref(ref) { ref.do_something(); }
~do_guard() { ref.clean(); }
};
int main()
{
foo c;
{
do_guard guard(c);
// do something
} // guard.~do_guard() will call c.clean() automatically
}
You can make do_something return something that gets its destructor called at the end of the scope:
class foo;
struct cleaner {
foo& f;
cleaner(foo& f) : f{f} {}
~cleaner();
};
class foo
{
public:
cleaner do_something() { return *this; }
void clean() {}
};
cleaner::~cleaner() { f.clean(); }
int main()
{
foo c;
{
auto x = c.do_something();
// do something
} // x calls c.clean() automatically
}
I am fairly new to C++ (coming from Java/PHP). Basically, I need to create a container class that will hold a reference of a unique/shared pointer to a virtual class instance (Base class). I am unable to get this piece of code to compile (I am using MSVC 2015).
The compiler error is:
error C2280: 'std::unique_ptr<Base,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function
Here is a sample application to reproduce the issue:
#include <iostream>
#include <memory>
class Base {
public:
virtual void foo() const = 0;
virtual void bar() const = 0;
};
class Derived : public Base {
public:
void foo() const override {
std::cout << "foo" << std::endl;
};
void bar() const override{
std::cout << "bar" << std::endl;
};
};
class ContainerUnique {
public:
ContainerUnique() {
ptr = nullptr;
}
void assignPtr(const Base &instance) {
auto ptr = std::make_unique<Base>(instance);
ptr.swap(ptr);
};
std::unique_ptr<Base> getPtr() {
return ptr;
};
private:
std::unique_ptr<Base> ptr;
};
class ContainerShared {
public:
ContainerShared() {
ptr = nullptr;
}
void assignPtr(const Base &instance) {
auto ptr = std::make_shared<Base>(instance);
ptr.swap(ptr);
};
std::shared_ptr<Base> getPtr() {
return ptr;
};
private:
std::shared_ptr<Base> ptr;
};
int main() {
Derived derived1 = Derived();
Derived derived2 = Derived();
ContainerUnique cu = ContainerUnique();
ContainerShared cs = ContainerShared();
cu.assignPtr(derived1);
cs.assignPtr(derived2);
std::unique_ptr<Base> uptr = cu.getPtr();
std::shared_ptr<Base> sptr = cs.getPtr();
return 0;
}
Please advice
You should think about object ownership, and where objects live (stack or heap), neither of which you may have had to focus on in Java.
Because ContainerUnique has a unique_ptr member, I infer that it is intended to own the pointed-to object. It is being given the obligation to delete it. This is inconsistent with the rest, because derived1 is on the stack, so has no need to be owned by anything, and cannot be deleted. Instead, suppose we created derived1 on the heap:
auto derived1 = std::make_unique<Derived>();
That creates it on the heap, so that it needs managing, and identifies us as owning the object by storing its pointer in a unique_ptr. To transfer ownership with a unique_ptr, we have to tweak the interface:
// Interface
void ContainerUnique::assignPtr(std::unique_ptr<Base> instance);
// Call site
cu.assignPtr(std::move(derived1));
If we take a raw reference or pointer, there is nothing in the interface or the call site to reflect the intended change in ownership. If we take a reference-to-Base, and call std::make_unique we are making a copy, and making a copy of a Base (losing any Derived data). Taking a unique_ptr is probably the clearest way to communicate ownership transfer.
Putting it together:
#include <memory>
struct Base {
virtual void foo() const = 0;
virtual void bar() const = 0;
};
struct Derived : Base {
void foo() const override { }
void bar() const override { }
};
class ContainerUnique {
public:
void assignPtr(std::unique_ptr<Base> instance) {
ptr.swap(instance);
};
std::unique_ptr<Base> getPtr() {
return std::move(ptr);
};
private:
std::unique_ptr<Base> ptr;
};
int main() {
auto derived1 = std::make_unique<Derived>();
auto cu = ContainerUnique();
cu.assignPtr(std::move(derived1));
auto uptr = cu.getPtr();
}
Question for C++ experts: I've got a library function expecting a shared_ptr<T> and I'd like to call this function within T. I know share_from_this is the correct way to go, but I can't get my head around it (and how to use it properly).
I've come up with a trick and I'd like to know if its safe (no UB). If it's not, could you explain me how to use share_from_this in my case?
#include <memory>
template<class T>
void library_function(std::shared_ptr<T>)
{}
struct A {
std::shared_ptr<A> share()
{
return std::shared_ptr<A>(this, [](A*){});
}
void operator()()
{
library_function(share());
}
};
int main()
{
A a;
a();
}
First of all , the object you want to share_from_this needs to be previously shared object and managed by std::shared_ptr. Ensuring that, classes that allow it need publicly inherit from std::enable_shared_from_this<A>. Next, if you want to create shared pointer from this you need to use method shared_from_this().
With your current code, it's safe.
However, if library_function stores that shared_ptr to use later and a is destroyed because of out of scope. It's undefined behavior. It's not safe then. This sample code is not much different from your code but it has undefined behavior in the second call:
template<class T>
void library_function(std::shared_ptr<T> t)
{
static std::shared_ptr<T> s;
if (!s) {
s = t;
}
if (s) s->do_something();
}
struct A {
std::shared_ptr<A> share()
{
return std::shared_ptr<A>(this, [](A*){});
}
void operator()()
{
library_function(share());
}
void do_something() {
}
};
int main()
{
// This emulates some function call and go out of scope
{
A a;
a();
}
// This call is undefined behavior
library_function(std::shared_ptr<A>{});
}
The right way to do it is something like this:
#include <memory>
#include <iostream>
template<class T>
void library_function(std::shared_ptr<T> t)
{
static std::shared_ptr<T> s;
if (!s) {
s = t;
}
if (s) s->do_something();
}
struct A : std::enable_shared_from_this<A> {
~A() {std::cout << "Destructed\n"; }
std::shared_ptr<A> share()
{
return shared_from_this();
}
void operator()()
{
library_function(share());
}
void do_something() {
std::cout << "do_something\n";
}
};
int main()
{
// This emulates some function call and go out of scope
{
std::shared_ptr<A> a = std::make_shared<A>();
(*a)();
}
library_function(std::shared_ptr<A>{});
}
You should derive your class from std::enable_shared_from_this. Make sure your object is managed by a std::shared_ptr.
#include <memory>
template<class T>
void library_function(std::shared_ptr<T>)
{}
struct A : public std::enable_shared_from_this<A> {
void operator()()
{
library_function(shared_from_this());
}
};
int main()
{
auto a = std::make_shared<A>();
a->operator()();
}
Your class should derive from std::enable_shared_from_this<>, then you can call this->shared_from_this() to get a shared_ptr<> to it.
For example:
class foo : std::enable_shared_from_this<foo> {
public:
void bar() {
call_some_func(this->shared_from_this());
}
};
So call_some_func() will receive a shared pointer to the foo instance. This will work as the original instance is already in a shared pointer, i.e. the instance is created as:
auto foo_inst = std::make_shared<foo>();
I have been experimenting with abstract types.
The code below gives me a desired effect.
class base{
public:
virtual void do_stuff() = 0;
};
class derived: public base{
public:
void do_stuff(){/*stuff*/}
};
class manager{
vector<shared_ptr<base>> ptrs;
public:
void add(base* ptr){
ptrs.emplace_back(ptr);
}
};
manager foo;
foo.add(new derived());
Fine and dandy, but it's awkward because the user is not only dealing with pointers, but has to use new without ever calling delete. My question is if there's a way I can implement this where the user of manager doesn't ever have to deal with pointers or new.
foo.add(derived()); //example
My attempts to implement this end up as:
class manager{
vector<shared_ptr<base>> ptrs;
public:
void add(base& ref){
ptrs.emplace_back(&ref);
}
};
But, the compiler says no known conversion from 'derived' to 'base&'. I have no idea how to make a reference to base compatible with a reference to derived. How do I get around this?
Pass unique_ptr
Your add function takes ownership of this object. A safe way of passing ownership is to pass unique_ptr.
Using a unique_ptr is fairly flexible because you can construct a shared_ptr from a unique_ptr or if you change your mind in the future you can store the unique_ptr directly.
class manager{
vector<shared_ptr<base>> ptrs;
public:
void add(std::unique_ptr<base> ptr){
ptrs.emplace_back(std::move(ptr));
}
};
manager foo;
foo.add(std::make_unique<derived>());
Using a temporary std::unique_ptr you avoid the owning raw pointer that is not exception safe. By using make_unique you can avoid writing new.
Live demo.
Pass a Factory
Another option if the caller really doesn't want to have to deal with any kind of pointer is to pass some sort of Factory that the add function uses to construct the object. The Factory could simply be a static create function on the derived class itself:
using Factory = std::function<std::unique_ptr<base>()>;
class manager{
std::vector<std::shared_ptr<base>> ptrs;
public:
void addUsing(const Factory& factory){
ptrs.emplace_back(factory());
}
};
class derived : public base {
public:
...
static std::unique_ptr<derived> create() {
return std::make_unique<derived>();
}
};
manager foo;
foo.addUsing(derived::create);
Live demo.
You can let your add() function be passed the arguments to be used in the construction of type T, where T is specified as the type of a subclass.
template <typename T, typename... TArgs>
void add(TArgs&&... args)
{
ptrs.emplace_back(std::make_shared<T>(std::forward<TArgs>(args)...));
}
Which can then be called as follows:
bm.add<derived_a>( "hello" ); // derived_a constructor takes a string
bm.add<derived_b>( 42 ); // derived_b constructor takes an int
Full example
#include <string>
#include <vector>
#include <memory>
class base
{
public:
virtual void f() = 0;
};
class derived_a : public base
{
public:
derived_a( std::string const& s ) : s_{ s } {}
void f() override { std::cout << "derived_a::string = " << s_ << '\n'; }
private:
std::string s_;
};
class derived_b : public base
{
public:
derived_b( int i ) : i_{ i } {}
void f() override { std::cout << "derived_b::int = " << i_ << '\n'; }
private:
int i_;
};
class base_manager
{
public:
template <typename T, typename... TArgs>
void add( TArgs&&... args )
{
ptrs.emplace_back( std::make_shared<T>( std::forward<TArgs>( args )... ) );
}
void print() { for ( auto& d : ptrs ) d->f(); }
private:
std::vector<std::shared_ptr<base>> ptrs;
};
int main()
{
base_manager bm;
bm.add<derived_a>( "hello" );
bm.add<derived_b>( 42 );
bm.print();
}
You can't pass a temporary (an r-value) to a non-const reference. Also you try to take the address of that temporary object, which will in the end produce a dangling pointer and undefined behavior.
Assuming you want to pass an object of unknown runtime type to the manager:
One thing you can do is using some sort of polymorphic copy mechanism (like a virtual clone method) and make an internal copy of the object on the heap (it has to be polymorphic, to avoid object slicing).
class base {
public:
virtual void do_stuff() = 0;
virtual shared_ptr<base> clone() const = 0;
virtual ~base()=default;
};
class derived : public base {
int data;
public:
derived() :data(0) {};
derived(const derived& other) :data(other.data)
{};
virtual shared_ptr<base> clone() const override {
return make_shared<derived>(*this);
};
void do_stuff() {/*stuff*/ }
};
class manager {
vector<shared_ptr<base>> ptrs;
public:
void add(const base& obj) {
ptrs.emplace_back(obj.clone());
}
};
int main() {
manager foo;
foo.add(derived());
}
without the clone, it would look something like this:
void add(const base& obj) {
if (typeid(obj)== typeid(derived) ){
ptrs.emplace_back(make_shared<derived>(static_cast<const derived&>(obj)));
}
else if (typeid(obj) == typeid(derived2)) {
...
}
Your original question seems to be concerned over the fact that the user/caller creates a pointer and hands it off and never deletes it. My example below, simply makes it explicit to the user that he can hand it off and forget about it. In otherwords, require the user to pass a shared_ptr...
#include <stdlib.h>
#include <vector>
#include <memory>
using namespace std;
class base{
public:
virtual void do_stuff() = 0;
};
class derived : public base{
public:
void do_stuff(){/*stuff*/ }
};
class manager{
vector<shared_ptr<base>> ptrs;
public:
void add(shared_ptr<base> ptr){
ptrs.emplace_back(ptr);
}
};
int main()
{
manager foo;
shared_ptr<derived> bp(new derived()); //require the user supply a smart pointer
foo.add(bp);
return 0;
}
This is simpler than the other posts, and may not be as forward thinking, but it does not require the derived class to implement additional base members. In many cases, it is may be enough.
I have a struct like this one:
struct foo
{
IBar* ptr;
};
which is part of a foo object with a long lifetime. Users often get instances of those objects in different callbacks and sometimes they inject stuff into the IBar* in certain places, use it in later callbacks, free it eventually. (IBar has virtual void free() { delete this; } which can be overridden of course).
The problem is I want to transition my users to the possibility of having more than one IBar* per foo struct and I want to make the transition smooth. One idea for making the transition smooth is changing the foo struct as follows:
struct foo
{
foo()
{
ptr = reinterpret_cast<IBar*>(new IBar*[N]);
memset(ptr, 0, sizeof(IBar*)*N);
}
IBar*& getBarPtr(size_t offset)
{
return reinterpret_cast<IBar**>(ptr)[offset];
}
IBar* ptr;
};
My idea is that this way, anyone using the old style where they expect there to be only one IBar* should fallback on using the first of the N transparently in the usual way of using it:
someFoo.ptr = new iImplementIBar(...);
but those users who begin to transition to new usage can get their offset and instead do
someFoo.getBarPtr(myOffset) = new iImplementIBar(...);
the problem, though, is that foo had a reset method which used to do this:
void reset() {
if (ptr)
{
ptr->free();
ptr = 0;
}
}
which this idea replaces with this:
void reset() {
IBar** ptrs = reinterpret_cast<IBar*>(ptr);
for (size_t i = 0; i < N; ++i)
if (ptrs[i])
{
ptrs[i]->free();
ptrs[i] = 0;
}
}
and the functionality of the free in the above seems to be lost. Is there a way to make this work? Or what goes wrong?
If you really must do this without implementing a newer interface, why not have something like this:
struct foo
{
IBar **bars; // or better yet: std::array or std::vector if size of N is fixed.
IBar *ptr;
IBar *getBar(int index)
{
...
}
...
};
That way users of the existing 'foo' interface continue to use ptr but the new bars interface is also available for those who wish to use it.
Without knowing more it's hard to know whether the above design makes sense.
Without recommending using this complicated and manual lifetime management design, it is possible to build a dummy IBar that will forward to the first IBar in the set while freeing the whole set.
#include <iostream>
#include <new>
// existing:
struct IBar
{
virtual void method() =0;
virtual void free() =0;
};
struct Bar : public IBar
{
virtual void method() { }
virtual void free() { delete this; }
};
struct foo
{
virtual void reset() { if (ptr) {ptr->free();}}
IBar* ptr;
};
// proposed:
struct fooset;
struct foosetwrap : public IBar
{
virtual void method();
virtual void free();
fooset* ptrOwner;
};
struct fooset : public foo
{
fooset(IBar** begin, IBar** end) : ptrBegin(begin) , ptrEnd(end)
{ wrapper.ptrOwner = this; ptr = &wrapper; }
IBar** begin(){return ptrBegin;}
IBar** end(){return ptrEnd;}
virtual void reset() {for(auto& expired : *this) { if (!!expired) { expired->free(); }}}
private:
foosetwrap wrapper;
IBar** ptrBegin;
IBar** ptrEnd;
};
void foosetwrap::method() { (*(ptrOwner->begin()))->method(); }
void foosetwrap::free() { ptrOwner->reset(); }
int wmain(int argc, wchar_t* argv[])
{
IBar* bars[]={new(std::nothrow) Bar(),new(std::nothrow) Bar()};
fooset set(std::begin(bars), std::end(bars));
set.ptr->method();
set.ptr->free();
return 0;
}