I have a struct
struct A {
void f() {}
void g() {}
};
and a custom smart pointer holding a pointer to A:
struct P {
...
A* a;
};
I would like to write P in such a way that that A::f() does not get called when I write
P p;
p->f();
Instead an overloaded function should be called. However, A::g() should still get called when I write
p->g();
I was hoping that I can achieve this by overloading P::operator-> but I didn't succeed. Any suggestions?
Edit: Here is what I tried:
#include <iostream>
struct A {
void f() {}
void g() {}
};
struct P {
struct Wrapper
{
Wrapper(A* aa) : _a(aa) {}
void f()
{
std::cout << "Overloaded\n";
}
A* operator->()
{
return _a;
}
private:
A* _a;
};
Wrapper operator->()
{
return Wrapper(a);
}
private:
A* a;
};
main()
{
P p;
p->f();
}
But this prints nothing at all because when I call p->f(), Wrapper::operator-> gets called instead of Wrapper::f().
Your P::operator-> would generally return an A* raw pointer. To get what you want, you need a proxy object that can be returned instead, which implements those functions.
class A_proxy
{
A* p;
public:
A_proxy(A* ptr) : p(ptr) {}
void f() { /* do whatever crazy stuff you want here */ }
void g() { p->g(); }
};
A_proxy* P::operator->()
{
return &m_proxy;
}
Here's an alternate method based on objections raised in the comments. This one might run into undefined behavior because of the type punning of the pointer though.
struct A_proxy : public A
{
void f() { /* as before, crazy stuff here */ }
};
A_proxy* P::operator->()
{
return static_cast<A_proxy*>(a);
}
Related
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.
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 want to make 'lazy construct' in a C++ class, a simple method to do that is something like this:
#include "b.hpp" // class B
class A {
public:
// invoke B() in b.hpp, this constructor do not actually do init
A(int v_in) : v(v_in) {}
void foo() {
if(flag == false) {
b = create_B_obj();
flag = true;
}
}
private:
B create_B_obj() {
// some expensive ops
//...
}
private:
bool flag = false;
B b;
int v;
};
But a existing problem is that B may not contain a default constructor (B()), so how can I do 'lazy construct' in this case?
BTW: class B in my project is something like a socket which need to do connect or do bind-like calls, so I want to put these expensive ops lazy.
Use pointer, preferably smart pointer.
class A
{
public:
void foo() {
if( pb == nullptr ) {
pb.reset(create_B_obj());
}
}
private:
B* create_B_obj(); //or return std::unique_ptr
private:
std::unique_ptr<B> pb;
int v;
};
You could avoid the dynamic allocation if you use placement-new instead, in which case you need custom deleter with std::unique_ptr:
class A
{
public:
void foo() {
if( pb == nullptr ) {
pb.reset(create_B_obj());
}
}
private:
B* create_B_obj()
{
return new (buffer) B( /* arguments */);
}
private:
std::unique_ptr<B, PlacementNewDeleter> pb;
alignas(B) char buffer[sizeof(B)]; //buffer used by placement new
int v;
};
where PlacementNewDeleter defined as:
struct PlacementNewDeleter
{
template<typename T>
void operator(T const *obj) const { obj->~T(); }
};
Hope that helps.
If you don't have access on the B class, then the easier way to do this is to use a pointer.
std::unique_ptr<B> b;
Then if your foo method:
B foo()
{
if (! b)
b.reset(new B(/* params */));
// or b.reset(create_B_obj());, which should return a pointer (may also return an unique_ptr)
return b;
}
The std::unique_ptr overloads operator bool and manages the memory so you don't have to delete.
Note: I changed the return type of the foo method as it seems more logical like this.
This might be a case for the switch-off rule explained in C++ coding standards and I am wondering if I am doing it correctly. I am wondering because I still have if-clauses in the switching function.
Class A never gets instantiated directly, it's always either B or C that get dynamically created and uniformly handled through a (shared) pointer to A. foo switches and selects the operation depending on whether it's an B or C.
class A {
public:
virtual ~A(){}
};
class B : public A {};
class C : public A {};
typedef std::shared_ptr<A> Aptr;
typedef std::shared_ptr<B> Bptr;
typedef std::shared_ptr<C> Cptr;
template<class T>
std::shared_ptr<T> get(const Aptr& pA) {
return std::dynamic_pointer_cast< T >( pA );
}
void foo( const Bptr& pB ) {
std::cout << "operate on B\n";
}
void foo( const Cptr& pC ) {
std::cout << "operate on C\n";
}
void foo( const Aptr& pA ) {
if ( auto x = get<B>(pA) ) {
foo(x);
return;
}
if ( auto x = get<C>(pA) ) {
foo(x);
return;
}
assert(!"oops");
}
int main()
{
Aptr pA( new C );
foo( pA );
}
My question is whether void foo( const Aptr& pA ) can be implemented more elegantly. That could mean without if. Is throwing in get and catching in foo recommended in this situation?
Unless you have good reasons for doing otherwise (and if you have them, your code does not show them), this seems to me like the typical use case for dynamic polymorphism achieved through a virtual function:
class A
{
public:
virtual ~A() {}
virtual void foo() = 0;
};
class B : public A
{
virtual void foo()
{
std::cout << "operate on B\n";
}
};
class C : public A
{
virtual void foo()
{
std::cout << "operate on B\n";
}
};
Besides, in C++11 it is preferable to use std::make_shared<>() over the construction of a shared_ptr with a naked new allocation (again, unless you have good reasons to do otherwise):
int main()
{
Aptr pA = std::make_shared<C>();
pA->foo();
}
If you have reasons not to use virtual functions and prefer a different, non-intrusive kind of polymorphism, you may use Boost.Variant in combination with boost::static_visitor. This does not even require B and C to be related.
#include <boost/variant.hpp>
#include <memory>
#include <iostream>
class B /* ... */ {};
class C /* ... */ {};
// ...
typedef std::shared_ptr<B> Bptr;
typedef std::shared_ptr<C> Cptr;
struct foo_visitor : boost::static_visitor<void>
{
void operator () (Bptr p)
{
std::cout << "operate on B\n";
}
void operator () (Cptr p)
{
std::cout << "operate on C\n";
}
};
int main()
{
boost::variant<Bptr, Cptr> ptr;
ptr = std::make_shared<C>();
foo_visitor v;
ptr.apply_visitor(v);
}
This approach is pretty similar to the one you chose, except that Boost.Variant also makes sure you are not forgetting to include a handling case for each of the values the variant could possibly assume (in this case, Bptr and Cptr).
Just use virtual member functions. There's no substitute for the real thing
class A {
public:
virtual ~A(){}
virtual void foo() = 0;
};
class B : public A {
public:
virtual void foo() {
std::cout << "operate on B\n";
}
};
class C : public A {
public:
virtual void foo() {
std::cout << "operate on C\n";
}
};
and pick a good C++ introductory book.
There is a class
class A {
public:
A() {};
private:
void func1(int) {};
void func2(int) {};
};
I want to add a function pointer which will be set in constructor and points to func1 or func2.
So I can call this pointer (as class member) from every class procedure and set this pointer in constructor.
How can I do it?
class A {
public:
A(bool b) : func_ptr_(b ? &A::func1 : &A::func2) {};
void func(int i) {this->*func_ptr(i);}
private:
typedef void (A::*func_ptr_t_)();
func_ptr_t_ func_ptr_;
void func1(int) {};
void func2(int) {};
};
That said, polymorphism might be a better way to do whatever you want to do with this.
Add a member variable
void (A::*ptr)();
set it in the constructor
ptr=&A::func1;
(or use the initializer list) and call it in methods of A:
(this->*ptr)();
I compiled and ran this code. The various members need to be public so you can pass them into the constructor. Otherwise, here you go.
However, I agree with other posters that this is almost definitely a bad thing to do. ;) Just make invoke pure virtual, and then make two subclasses of A which each override invoke().
#include <iostream>
using namespace std;
class A;
typedef void(A::*MyFunc)(int) ;
class A {
public:
A() {}
A(MyFunc fp): fp(fp) {}
void invoke(int a)
{
(this->*fp)(a);
}
void func1(int a) { cout << "func1 " << a << endl; }
void func2(int a) { cout << "func2 " << a << endl; }
private:
MyFunc fp;
};
int main()
{
A* a = new A( & A::func1 );
a->invoke(5);
A* b = new A( & A::func2 );
b->invoke(6);
}
See boost::function for a way to handle function and class member pointers in a more OO/C++ manner.
For example (from the documentation) :
struct X
{
int foo(int);
};
boost::function<int (X*, int)> f;
f = &X::foo;
X x;
f(&x, 5);
I suggest you use functor(or function object), rather than function pointer, because the former is safer, and function pointer can be difficult or awkward to pass a state into or out of the callback function
A functor is basically a re-implementation of operator() of class A, for very detailed description please refer to Wikipedia: http://en.wikipedia.org/wiki/Function_object
The code should be something like this:
class A {
public:
A() {};
void operator()(int function_index, int parameter) {
if(function_index == 1)
func1(parameter);
else if(function_index == 2)
func2(parameter);
else
{ //do your other handling operation
}
}
private:
void func1( int ) {};
void func2( int) {};
};
By using that class:
A a;
a(1, 123); //calling func1
a(2, 321); //calling func2
Why do you think it's a bad thing to do. I just need one function pointer and I don't want to create two subclasses for this. So why is it so bad?
Some example...
class A; // forward declaration
typedef void (A::*func_type)(int);
class A {
public:
A() {
func_ptr = &A::func1;
}
void test_call(int a) {
(this->*func_ptr)(a);
}
private:
func_type func_ptr;
void func1(int) {}
void func2(int) {}
};