Reference code:
#include <vector>
#include <iostream>
class Func {
public:
virtual void call() {
std::cout<< "Func -> call()" << std::endl;
}
};
class Foo : public Func {
public:
void call() {
std::cout<< "Foo -> call()" << std::endl;
}
};
class Bar : public Func {
public:
void call() {
std::cout<< "Bar -> call()" << std::endl;
}
};
int main(int argc, char** argv) {
std::vector<Func> functors;
functors.push_back( Func() );
functors.push_back( Foo() );
functors.push_back( Bar() );
std::vector<Func>::iterator iter;
for (iter = functors.begin(); iter != functors.end(); ++iter)
(*iter).call();
}
When run that code, it produces the following output on my computer:
$ ./test
Func -> call()
Func -> call()
Func -> call()
Would there be any way to ensure that the correct virtual function is called in this instance? I'm new at C++ but my best guess is that here:
(*iter).call();
It's being cast to a Func object. Is this correct?
You should use a shared_ptr or unique_ptr to hold the elements of a collection of polymorphic type.
As your code is written now the Foo and Bar instances are cooerced (copy constructed) into an instance of type Func to fit into the vector. (The reason is that vector stores its elements immediately by fixed-sized value for performance, however polymorphic subclasses are of a arbitrarily larger size unknown at compile-time, so it can only store the base class.)
This is better:
int main(int argc, char** argv) {
vector<shared_ptr<Func>> functors;
functors.push_back( make_shared<Func>() );
functors.push_back( make_shared<Foo>() );
functors.push_back( make_shared<Bar>() );
for (auto functor : functors)
functor->call();
}
In the above a reference-counted pointer is used to implicitly share the hetrogeneous subclasses of Func in the vector. (This indirection allows arbitrarily sized subclasses of Func to be stored by address indirection.)
Also, you may want to take a look at std::function and std::bind, rather than rolling your own functor type.
Another thing to look at would be perfect forwarding and varadic templates.
update: For old compiler:
int main(int argc, char** argv) {
vector<std::tr1::shared_ptr<Func> > functors;
functors.push_back( std::tr1::make_shared<Func>() );
functors.push_back( std::tr1::make_shared<Foo>() );
functors.push_back( std::tr1::make_shared<Bar>() );
for (size_t i = 0; i < functors.size(); ++i)
functors[i]->call();
}
the vector only holds the type Func by value, meaning that all your temporals Foo and Bar are sliced and casted to the base Func type
you need to change to something like std::vector< Func* > and dynamically allocate the derived classes instances in order for polymorphic dispatch to work
If you are completely sure that you won't pass this vector to other functions after this function returns, as an optimization you might want to allocate the instances in the stack:
std::vector< Func* > v;
Bar b;
Foo f;
v.push_back( &b);
v.push_back( &f);
your std::vector is storing Func objects - this means that when you call
functors.push_back( Foo() );
functors.push_back( Bar() );
you're creating Foo and Bar objects, then "slicing" those objects as they are copied into Func objects.
If you'd like to use Foo and Bar polymorphically, then a more typical pattern would be to store a vector of some pointer type (Preferably not "raw" pointers though), for example
std::vector< std::unique_ptr<Func> >
std::vector< std::shared_ptr<Func> >
Or, if you really have to.. (But only if you're using an older compiler which doesn't have shared_ptr or unique_ptr)
std::vector< Func* >
In C++ polymorphism works only with pointers and references, while the vector stores directly instances of objects. When you call push_back the copy constructor of Func is called, which builds the Func object that is stored inside the vector.
This is called object slicing, you can learn more about it with a quick search in StackOverflow.
The solution would be to store pointers (or, even better, smart pointers) to your objects, which should be allocated elsewhere (probably on the heap).
In general, instances of subclasses may be larger than those of their superclass, so you should not expect the subclasses to fit into your vector's slot.
And push_back probably will call internally a copy constructor (of the Func class, since you have vector<Func>) so the internal vector slots are indeed Func not of some other classes.
Your problem is that you have a vector of Func, but methods are called polymorphically only through references or pointers.
there is a very simple way of making vector without using pointers by creating child class which will inherit Class A and Class B
#include <iostream>
#include <vector>
using namespace std;
struct BASE {
string name = "Base class ";
};
struct A : BASE {
string a = " class a ";
};
struct B : BASE {
string b = " class b ";
};
struct C : A, B{
//using base name from A or B// yeah is hardcoded
string name = A::name;
};
int main()
{
C c;
c.a = "s";
c.b = "h";
vector<C> vec;
vec.push_back(c);
c.b = "j";
vec.push_back(c);
cout << vec[0].a << endl;
cout << vec[0].b << endl;
cout << vec[0].name << endl;
cout << vec[1].a << endl;
cout << vec[1].b << endl;
cout << vec[1].name << endl;
return 0;
}
Related
I would like to perform a down casting at execution time.
For what I read, if I want to do it, I need to compare the typeid of my polymorphic pointer with those of my derived classes, then do the casting in the correct type.
Plus, let's assume that I have a large number of derived classes.
This implies I have to write a long switch or list of if.
I would like to reduce this effort by using a list of classes to check.
This could look like:
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <map>
using namespace std;
class BaseShapes
{
virtual int run() = 0;
};
class ClassRectangle : public BaseShapes
{
int run()
{
std::cout << "I am a Rectangle. " << std::endl;
return 0;
}
float get_length () {return 12.4;};
float get_width() {return 6.2;};
};
class ClassCircle : public BaseShapes
{
int run()
{
std::cout << "I am a Cricle. " << std::endl;
return 0;
}
float get_diameter() {return 5.3;};
};
float function_only_for_Rectangle(ClassRectangle *rectangle)
{
// a function coming from a library that I cannot touch and that requires a derived type.
// But for the example I do something dummy!
return rectangle->get_length()
};
auto downcast_function (auto *p)
{
enum ListOfTypes {
ClassCircle,
ClassRectangle,
// and a lot more differents classes
};
for ( int fooInt = ClassCircle; fooInt < ClassRectangle; fooInt++ )
{
ListOfTypes fooItem = static_cast<ListOfTypes>(fooInt);
if (typeid(p) == typeid(fooItem))
{
auto pCasted =dynamic_cast<fooItem>(p);
return pCasted;
}
}
std::cout<< "downcast_function warning: no typeid is matching !" << std::endl;
return p;
};
int main(void)
{
// Beginning of main.
cout << "(Start)" << endl;
std::unique_ptr<BaseShapes> Shape1(new ClassRectangle());
auto p=Shape1.get();
//function_only_for_Rectangle(p); // not working since p is of type BaseShapes*
auto pbis=downcast_function(p); // should be of type ClassRectangle*
function_only_for_Rectangle(pbis);
// End of the main.
cout << "(End) " << endl;
return 0;
}
// EoF
So how can I write the downcast_function ? Or in other words, how can I iterate over a list of class types in order to make a typeid comparison and a casting ?
More details:
I agree that in this dummy example, I could simply override a function for each derived class and that is a much better way to deal with polymorphism. But I need to downcast, this is a constrain coming from a more complex problem where they are things that I am not allowed to changed. So, the question here is not why downcast but how.
To give a bit more details about my constrains are:
To start from a base pointer.
Get a derived pointer and give it to an external function (here called function_only_for_Rectangle, so I cannot modify this function).
I cannot do a simple and direct dynamic_cast<ClassRectangle>(p) because the type of p (or equivalently Shape1) will change at running time. This means that Shape1 can have "randomly" any derived type from BaseShapes. So I need something "automatic" and this is why I was thinking about iterate over all derived types and downcast according to the typeid match (but I am open to better ideas).
All the classes can modified if needed.
You say "polymorphic" but what you want to do is the opposite of it.
Instead of trying to work against polymorphism you could actually use it. If all subclasses have their own implementation of a virtual function then the caller does not need to care what the actual dynamic type of the object is. That is runtime polymorphism in a nutshell.
I suppose the naming for run is only for the example. Give it a better name, supply a default implementation in the base class, implement specific behavior in ClassRectangle and let the caller call it. No need to cast.
class BaseShapes
{
virtual int do_something_rectangly() { return 0;}
~virtual BaseShapes() = default;
};
class ClassRectangle : public BaseShapes
{
int do_something_rectangly() override
{
std::cout << "I am a Rectangle. " << std::endl;
return 0;
}
};
class ClassCircle : public BaseShapes
{
// does not override do_something_rectangly()
};
int function_for_any_base_shape(BaseShapes& s)
{
return s.do_something_rectangly();
};
int main(void)
{
// Beginning of main.
cout << "(Start)" << endl;
std::unique_ptr<BaseShapes> Rec1(new ClassRectangle());
function_for_any_base_shape(*pbis);
cout << "(End) " << endl;
return 0;
}
Concerning your edit:
I cannot do a simple and direct dynamic_cast(p) because the type of p (or equivalently Shape1) will change at running time. This means that Shape1 can have "randomly" any derived type from BaseShapes. [...]
Either I misunderstand what you wrote completely or you misunderstand how dynamic_cast works. dynamic_cast does already check what the dynamic type of the object is:
BaseShapes* b1 = new ClassCircle;
if(ClassRectangle* d = dynamic_cast<ClassRectangle*>(b1))
{
// cast is sucessfull
function_only_for_Rectangle(d);
} else {
// dynamic type of b1 is not ClassRectangle
}
To call function_only_for_Rectangle you do not need to be able to cast to all subtypes of ClassBase. You only need to dynamic_cast to a pointer to ClassRectangle and check if the cast was sucesfull.
I commonly come across the need to create arrays or vectors of polymorphic objects. I'd usually prefer to use references, rather than smart pointers, to the base class because they tend to be simpler.
Arrays and vectors are forbidden from containing raw references, and so I've tended to use smart pointers to the base classes instead. However, there is also the option to use std::reference_wrapper instead: https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper
From what I can tell from the documentation, this is what one of its intended uses is, but when the topic of arrays containing polymorphic objects comes up, the common advice seems to be to use smart pointers rather than std::reference_wrapper.
My only thought is that smart pointers may be able to handle the lifetime of the object a little neater?
TL:DR; Why are smart pointers, such as std::unique_ptr seemingly preferred over std::reference_wrapper when creating arrays of polymorphic objects?
In very simple terms:
unique_ptr is the owner of the object. It manages the lifetime of the owned object
reference_wrapper wraps a pointer to an object in memory. It does NOT manage the lifetime of the wrapped object
You should create an array of unique_ptr (or shared_ptr) to guarantee the release of the object when it's not needed anymore.
If you are sufficiently motiviated, you can write a poly_any<Base> type.
A poly_any<Base> is an any restricted to only storing objects that derive from Base, and provides a .base() method that returns a Base& to the underlying object.
A very incomplete sketch:
template<class Base>
struct poly_any:private std::any
{
using std::any::reset;
using std::any::has_value;
using std::any::type;
poly_any( poly_any const& ) = default;
poly_any& operator=( poly_any const& ) = default;
Base& base() { return get_base(*this); }
Base const& base() const { return const_cast<Base const&>(get_base(const_cast<poly_any&>(*this))); }
template< class ValueType,
std::enable_if_t< /* todo */, bool > =true
>
poly_any( ValueType&& value ); // todo
// TODO: sfinae on ValueType?
template< class ValueType, class... Args >
explicit poly_any( std::in_place_type_t<ValueType>, Args&&... args ); // todo
// TODO: sfinae on ValueType?
template< class ValueType, class U, class... Args >
explicit poly_any( std::in_place_type_t<ValueType>, std::initializer_list<U> il,
Args&&... args ); // todo
void swap( poly_any& other ) {
static_cast<std::any&>(*this).swap(other);
std::swap( get_base, other.get_base );
}
poly_any( poly_any&& o ); // todo
poly_any& operator=( poly_any&& o ); // todo
template<class ValueType, class...Ts>
std::decay_t<ValueType>& emplace( Ts&&... ); // todo
template<class ValueType, class U, class...Ts>
std::decay_t<ValueType>& emplace( std::initializer_list<U>, Ts&&... ); // todo
private:
using to_base = Base&(*)(std::any&);
to_base get_base = 0;
};
Then you just have to intercept every means of putting stuff into the poly_any<Base> and store a get_base function pointer:
template<class Base, class Derived>
auto any_to_base = +[](std::any& in)->Base& {
return std::any_cast<Derived&>(in);
};
Once you have done this, you can create a std::vector<poly_any<Base>> and it is a vector of value types that are polymorphically descended from Base.
Note that std::any usually uses the small buffer optimization to store small objects internally, and larger objects on the heap. But that is an implementation detail.
Basically, a reference_wrapper is a mutable reference: Like a reference, it must not be null; but like a pointer, you can assign to it during its lifetime to point to another object.
However, like both pointers and references, reference_wrapper does not manage the lifetime of the object. That's what we use vector<uniq_ptr<>> and vector<shared_ptr<>> for: To ensure that the referenced objects are properly disposed off.
From a performance perspective, vector<reference_wrapper<T>> should be just as fast and memory efficient as vector<T*>. But both of these pointers/references may become dangling as they are not managing object lifetime.
Let's try the experiment:
#include <iostream>
#include <vector>
#include <memory>
#include <functional>
class Base {
public:
Base() {
std::cout << "Base::Base()" << std::endl;
}
virtual ~Base() {
std::cout << "Base::~Base()" << std::endl;
}
};
class Derived: public Base {
public:
Derived() {
std::cout << "Derived::Derived()" << std::endl;
}
virtual ~Derived() {
std::cout << "Derived::~Derived()" << std::endl;
}
};
typedef std::vector<std::reference_wrapper<Base> > vector_ref;
typedef std::vector<std::shared_ptr<Base> > vector_shared;
typedef std::vector<std::unique_ptr<Base> > vector_unique;
void fill_ref(vector_ref &v) {
Derived d;
v.push_back(d);
}
void fill_shared(vector_shared &v) {
std::shared_ptr<Derived> d=std::make_shared<Derived>();
v.push_back(d);
}
void fill_unique(vector_unique &v) {
std::unique_ptr<Derived> d(new Derived());
v.push_back(std::move(d));
}
int main(int argc,char **argv) {
for(int i=1;i<argc;i++) {
if(std::string(argv[i])=="ref") {
std::cout << "vector" << std::endl;
vector_ref v;
fill_ref(v);
std::cout << "~vector" << std::endl;
} else if (std::string(argv[i])=="shared") {
std::cout << "vector" << std::endl;
vector_shared v;
fill_shared(v);
std::cout << "~vector" << std::endl;
} else if (std::string(argv[i])=="unique") {
std::cout << "vector" << std::endl;
vector_unique v;
fill_unique(v);
std::cout << "~vector" << std::endl;
}
}
}
running with argument shared:
vector
Base::Base()
Derived::Derived()
~vector
Derived::~Derived()
Base::~Base()
running with argument unique
vector
Base::Base()
Derived::Derived()
~vector
Derived::~Derived()
Base::~Base()
running with argument ref
vector
Base::Base()
Derived::Derived()
Derived::~Derived()
Base::~Base()
~vector
Explanation:
shared: Memory is shared by different parts of the code. In the example, the Derived object is first owned by the d local var in the function fill_shared() and by the vector. When the code exits the scope of the function object is still owned by the vector and only when the vector goes finally away, the object is deleted
unique: Memory is owned by the unique_ptr. In the example, the Derived object is first owned by the d local var. However it must be moved into the vector, transferring the ownership. Same as before, when the only owner goes away, the object gets deleted.
ref: There's no owning semantics. The object is created as a local variable of the fill_ref() function, and the reference to the object can be added to the vector. However, the vector does not own the memory and when the code goes out of the fill_ref() function, the object goes away, leaving the vector pointing to unallocated memory.
I created some code to reproduce the problem:
#include "stdafx.h"
#include <iostream>
#include <vector>
class A
{
protected:
int m_X;
public:
A() {
std::cout << "in A ctor" << std::endl;
m_X = 0;
}
virtual void printX(){ std::cout << "in A " << m_X << std::endl; }
};
class B : public A
{
public:
B() {
std::cout << "in B ctor" << std::endl;
m_X = 1;
}
virtual void printX(){ std::cout << "in B " << m_X << std::endl; }
};
class As
{
public:
void AddA( const A &a ){ m_As.push_back( a ); }
void PrintXs()
{
for ( auto a : m_As )
{
a.printX();
}
}
private:
std::vector<A> m_As;
};
int _tmain(int argc, _TCHAR* argv[])
{
As as;
B b;
as.AddA( b );
as.PrintXs();
system("pause");
return 0;
}
The output of this is:
in A ctor
in B ctor
in A 1
I want "in B 1" instead of "in A 1". I'm sure my understanding of virtual is flawed. How must I change the code to call the B PrintX()? Note that there will be other classes that inherit from A so I really don't want to code a static call.
Thanks.
What you're doing is called slicing. This is where you take an object of a derived class and trim off everything that is not in the parent and assign it to the parent.
What you want to do is use polymorphism to do what you explained. To do this, change your vector from a copy of the object, to a ptr to the object.
If interested in more details, please use the links provided, the information included in them seems to be very complete.
The quick fix is to change your As class to the following:
class As
{
public:
void AddA( A &a ){ m_As.push_back( &a ); }
void PrintXs()
{
for ( auto a : m_As )
{
a->printX();
}
}
private:
std::vector<A*> m_As;
};
When you use std::vector<A> m_As;, the vector can only fit A objects. If you use pointers instead then polymorphism can work and call the correct printX function. However, this has the problem of dangling pointer if the lifetime of the pointed to object expires. To handle that it would be better to use a smart pointer class like std::unique_ptr.
Since you're passing objects by value you can not take advantages of polymorphism. Pass them by (smart) pointers or references.
std::vector<std::shared_ptr<A>> m_As;
// or
std::vector<std::unique_ptr<A>> m_As;
// or
std::vector<A*> m_As; // be careful of bare pointers
// or (since C++11)
std::vector<std::reference_wrapper<A>> m_As;
std::reference_wrapper magic!
For the last one, you can use std::reference_wrapper and std::ref:
class As
{
public:
void AddA(A &a){ m_As.push_back( std::ref(a) ); }
void PrintXs() const
{
for ( auto a : m_As )
{
a.get().printX();
}
}
private:
std::vector<std::reference_wrapper<A>> m_As;
};
Using last code, you don't have to change main code.
Live code
for ( const auto & a : m_As )
{
a.printX();
}
it will keep you from expanded copy and provide the B-instance instead of A-instance, appeared as copy.
Lets say I have heap allocated A*, which I want to pass as argument to boost::bind.
boost::bind is saved for later processing in some STL like container of boost::functions's.
I want to ensure A* will be destroyed at destruction of the STL container.
To demostrate:
A* pA = new A();
// some time later
container.push_back(boost::bind(&SomeClass::HandleA, this, pA);
// some time later
container is destroyed => pA is destroyed too
How can it be done?
EDIT
Maybe what I want is not that realistic.
I have raw pointer and function which receives the raw pointer. The call is delayed by means of boost::bind. At this point I want automatic memory management in case boost::bind want executed. I'm lazy, so I want to use "ready" smart-pointer solution.
std::auto_ptr looks like a good candidate, however ...
auto_ptr<A> pAutoA(pA);
container.push_back(boost::bind(&SomeClass::HandleA, this, pAutoA);
doesn't compile (see here)
auto_ptr<A> pAutoA(pA);
container.push_back(boost::bind(&SomeClass::HandleA, this, boost::ref(pAutoA));
pAutoA is destroyed, deleting underlying pA.
EDIT 02
In the mentioned container I will need to store misc "callbacks" with different arguments. Some of them are raw pointers to object. Since the code is old, I not always can change it.
Writing own wrapper for storing callbacks in container is last resort (while maybe the only one), hence bounty.
The idea of #pmjordan was already going in the right direction. You replied that you can't use shared_ptr, because you can't take ownership back from it once constructed. But that is not entirely correct: with shared_ptr's custom deleter mechanism, you can. This is how:
Assume these toy defintions for your A and f(A*):
struct A {
~A() { std::cout << "~A()" << std::endl; }
};
void f( A * a ) {
std::cout << "in f(A*)" << std::endl;
delete a;
}
Write a deleter that can be "switched off":
struct opt_delete {
bool m_delete;
opt_delete() : m_delete( true ) {}
template <typename T>
void operator()( T * t ) {
if ( m_delete ) delete t;
}
};
Then you can write a take() function that takes ownership of the shared_ptr payload again:
template <typename T>
T * take( const boost::shared_ptr<T> & sp ) {
opt_delete * d = boost::get_deleter<opt_delete>( sp );
assert( d );
assert( d->m_delete == true );
d->m_delete = false;
return sp.get();
}
(this will leave the payload in the remaining shared_ptr instances, but for your case, that's ok, and the assert()s cover the cases when it's not).
Now you can manually wrap f(A*) like this:
void f_sp( const boost::shared_ptr<A> & a ) {
f( take( a ) );
}
And finally, test the two scenarios:
int main( int argc, char * argv[] ) {
const boost::shared_ptr<A> a( new A, opt_delete() );
const boost::function<void()> func =
boost::bind( &f_sp, a );
if ( argc >= 2 && *argv[1] == '1' ) // call 'func'
func();
else
; // don't
return 0;
}
Executing the test program with a 1 argument will print
in f(A*)
~A()
and without (or any other argument), it will print
~A()
You can extend the test harness to put func into a container first, but it'll still be safe. The only thing that isn't safe in the case is calling the func copies more than once (but then you'll trigger the second assertion in take()).
EDIT: Note that this mechanism isn't thread-safe. To make it thread-safe, you need to supply opt_delete with a mutex to synchronise operator() with take().
I assume you mean you have some function, let's call it f() which takes an A*, which you then proxy with boost::bind? Can you change this function to accept a Boost/TR1 shared_ptr<A> instead? Using a shared_ptr (or, less likely, a C++98 std::auto_ptr) should solve your lifecycle problem.
Alternatively, if you can't change f itself, you could create a wrapper which accepts a shared_ptr<A>, pulls out the raw pointer and calls f with it. If you find yourself writing a lot of these wrappers, you may be able to create a template for generating them, assuming the function signatures are similar.
NB! This is UGLY!
Have just scrateched some proof of concept. Well, it does what requested, as far as I can see - but this stuff relies on const_cast assumption. If you decide to use something like that in your program, be ready to double check all copy constructions happening in your program all the time, and using valgrind to verify nothing is leaked/corrupted.
Trick is in defining you own wrapper class, that ignores const qualifiers and allows auto_ptr ownership transfer from const referenced auto_ptr. This can get crazy if you ll try, for example, copy vector itself.
So be sure to read carefuly about vector copy semantics, auto_ptr ownership transfer semantics and, best of all - just use shared_ptr :)
#include <iostream>
#include <boost/bind.hpp>
#include <algorithm>
#include <vector>
#include <boost/function.hpp>
class parameter_data
{
public:
~parameter_data()
{
std::cout << "~parameter_data()" << std::endl;
}
parameter_data()
{
std::cout << "parameter_data()" << std::endl;
}
};
void f( parameter_data* data )
{
std::cout << "Processing data..." << std::endl;
};
class storage_wrapper
{
private:
boost::function<void()> callable;
std::auto_ptr<parameter_data> data;
public:
storage_wrapper( const storage_wrapper& copy )
{
callable = const_cast< storage_wrapper&>(copy).callable;
data = const_cast< storage_wrapper&>(copy).data;
}
storage_wrapper( parameter_data *adata )
: data( adata )
{
callable = boost::bind( &f, adata );
}
storage_wrapper& operator=( const storage_wrapper& copy)
{
callable = const_cast< storage_wrapper&>(copy).callable;
data = const_cast< storage_wrapper&>(copy).data;
}
void operator()()
{
callable();
}
};
int main()
{
std::cout << "Start of program" << std::endl;
{
std::vector<storage_wrapper> container;
for ( int i = 0; i < 100; i++ )
container.push_back( storage_wrapper( new parameter_data() ) );
for ( int i = 0; i < 100; i++ )
container[i]();
}
std::cout << "End of program" << std::endl;
return 0;
}
It doesn't need to be very complex:
class MyContainer : public std::vector<boost::function<void ()> > {
public:
void push_back(boost::function<void ()> f, A *pA)
{ push_back(f); vec.push_back(pA); }
~MyContainer()
{ int s=vec.size; for(int i=0;i<s;i++) delete vec[i]; }
private:
std::vector<A*> vec;
};
It has one problem that you need to pass it to other functions via MyContainer & instead of std::vector reference, otherwise the original push_back can be called and it allows for cases where you can push_back without providing the A* pointer. Also it has no check for bind parameters to be the same A* object than pA. You can fix that by changing the push_back prototype:
template<class T>
void push_back(T *object, void (T::*fptr)(), A *pA)
{
push_back(boost::bind(fptr, object, pA)); vec.push_back(pA);
}
I have a class Model:
class Model
{
...
boost::shared_ptr<Deck> _deck;
boost::shared_ptr<CardStack> _stack[22];
};
Deck inherits from CardStack.
I tried to make _stack[0] point to the same thing that _deck points to by going:
{
_deck = boost::shared_ptr<Deck>(new Deck());
_stack[0] = _deck;
}
It seems that the assignment to _deck of _stack[0] results in a copy of _deck being made. (I know this because modifications to _stack[0] do not result in modifications to _deck.) How can I get them to point to the same thing?
Ok - no copy constructor is being called. I have verified this by implementing it and seeing if it gets called - it doesn't.
However - I have a function that operates on CardStack objects:
void TransferSingleCard(CardStack & src, CardStack & dst, Face f)
{
if( !src._cards.empty() )
{
src._cards.back().SetFace(f);
dst.PushCard(src._cards.back());
src._cards.pop_back();
}
}
Now - when I call:
{
TransferSingleCard(*_stack[DECK], _someotherplace, FACEDOWN);
std::cout << *_stack[DECK];
std::cout << *_deck;
}
I get this output (where std::cout on a CardStack will print out the size of that stack):
Num(103) TOP
Num(104) TOP
... so I've concluded (incorrectly?) that _stack[DECK] points to something different.
The Deck
class Deck : public CardStack
{
public:
Deck(int numsuits=2, StackIndex index = NO_SUCH_STACK );
Deck::Deck( const Deck & d);
int DealsLeft() const;
void RecalcDealsLeft();
private:
int _dealsleft;
};
Not clear what you are asking about - consider this code:
#include <iostream>
#include "boost/shared_ptr.hpp"
using namespace std;
struct A {
virtual ~A() {
cout << "destroyed" << endl;
}
};
struct B : public A {
};
int main() {
boost::shared_ptr<B> b( new B );
boost::shared_ptr<A> a;
a = b;
}
Only one "destroy" message appears, indicating that no copy has been made.
This example - derives from #Neil's answer, tries to emulate what you say is happening. Could you check that it works as expected (A and B have the same count) on your system.
Then we could try and modify this code or your code until they match.
#include <boost/shared_ptr.hpp>
#include <iostream>
class A {
public:
virtual ~A()
{
std::cerr << "Delete A" << std::endl;
}
int _count;
void decrement()
{
_count --;
}
};
class B : public A {
public:
virtual ~B()
{
std::cerr << "Delete B" << std::endl;
}
};
int main()
{
boost::shared_ptr<B> b(new B);
b->_count = 104;
boost::shared_ptr<A> a;
a = b;
a->decrement();
std::cerr << "A:" << a->_count << std::endl;
std::cerr << "B:" << b->_count << std::endl;
return 0;
}
EDIT:
So from the comment, we know the original pointers are correct, so now we need to trace.
Either:
log pointers to see when they change.
Use watchpoints in a debugger to see when the pointer changes.
Use a third shared pointer to see which pointer is changed.
Introduce a function that changes both pointers at the same time.
I think the problem is that you're assigning between different types here. boost::shared_ptr is a template and templates are not polymorphic even if the type in them is. So what's happening is that your compiler sees the assignment from boost::shared_ptr<Deck> to boost::shared_ptr<CardStack> and notices that it can make the assignment by calling the copy constructor for CardStack to duplicate the Deck object.
I think what you want the assignment to look like is something like this:
_stack[0] = boost::static_pointer_cast<CardStack>(_deck);
Which will do the conversion the way you expect it to.
I think you may want shared_array for _stack . . . Take a look at the documentation on shared_ptr;from boost.org, specifically:
http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/shared_ptr.htm
"Normally, a shared_ptr cannot
correctly hold a pointer to a
dynamically allocated array. See
shared_array for that usage."
Also, be aware of the T* get() function (not to be used without good reason) which returns the raw pointer being held by the managed pointer (shared_ptr in this case).