moving unique pointers between deques - c++

I have a container class for some unique pointers to objects.
I now need to take one of them, do something with them in a different class and hand over to another class (and at some point recycle them and put them back to the container ).
Below is the outline of the code. However I am getting confused with the right way to move unique pointers with functions:
using uptrPod = unique_ptr<Pod>;
using dqUptrPods = deque<uptrPods>;
class Container {
public:
Container() :
n_elements_( 500 )
{
for ( auto i = 0; i < n_elements_; i++ ) {
free_pods_.push_back( uptrPod( new Pod()) );
}
const uptrPod&& getPod() {
auto up_pod= std::move( free_pods_[0] );
free_pods_.erase( free_pods_.begin() );
return up_pod;
}
void returnPod( const uptrPod&& up_pod ) {
free_pods_.push_back( up_pod );
}
private:
long n_elements_;
dqUptrPods free_pods_;
};
class PodTracker {
void addPod( const uptrPod&& up_pod ) { dq_pods_.pushback( up_pod ); }
dqUptrPods dq_pods_;
};
class PodHandler {
void movePod() {
up_pod = std::move( container_->getPod() );
/// do stuff with pod
pod_tracker_->addPod( up_pod );
}
Container* container_;
PodTracker* pod_tracker_;
};
I am getting the error:
cannot bind std::unique_ptr l value to const uptrPod&& { aka const std::unique_ptr &&
How can I hand around the pointer between the classes?

Pass/return the std::unique_ptr instances by value, and explicitly use std::move:
uptrPod getPod() {
auto up_pod= std::move( free_pods_[0] );
free_pods_.erase( free_pods_.begin() );
return up_pod;
}
void returnPod( uptrPod up_pod ) {
free_pods_.push_back( std::move(up_pod) );
}
class PodTracker{
void addPod(uptrPod up_pod) { dq_pods_.push_back(std::move(up_pod)); }
dqSptrPods dq_pods_;
};
void movePod() {
// `std::move` is not necessary here, as `getPod()`
// is already a temporary (rvalue)
auto up_pod = container_->getPod();
/// do stuff with pod
pod_tracker_->addPod( std::move(up_pod) ) ;
}
example on wandbox
Note that const rvalue references do not make much sense - an rvalue reference.
The main purpose of rvalue references is to allow us to move objects instead of copying them. And moving the state of an object implies modification. As a result, the canonical signatures for the move constructor and the move assignment operator both take its argument as a non-const rvalue reference.
(From: "What are const rvalue references good for?")

Related

C++ Code reusability between copy constructor and assignment operator (=) [duplicate]

In c++ when classes contains dynamically allocated data it is usually reasonable to explicitly define copy constructor, operator= and destructor. But the activity of these special methods overlaps. More specifically operator= usually first does some destruction and then it does coping similar to the one in copy constructor.
My question is how to write this the best way without repeating the same lines of code and without the need for processor to do unnecessary work (like unnecessary copying).
I usually end up with two helping methods. One for construction and one for destruction. The first is called from both copy constructor and operator=. The second is used by destructor and operator=.
Here is the example code:
template <class T>
class MyClass
{
private:
// Data members
int count;
T* data; // Some of them are dynamicly allocated
void construct(const MyClass& myClass)
{
// Code which does deep copy
this->count = myClass.count;
data = new T[count];
try
{
for (int i = 0; i < count; i++)
data[i] = myClass.data[i];
}
catch (...)
{
delete[] data;
throw;
}
}
void destruct()
{
// Dealocate all dynamicly allocated data members
delete[] data;
}
public: MyClass(int count) : count(count)
{
data = new T[count];
}
MyClass(const MyClass& myClass)
{
construct(myClass);
}
MyClass& operator = (const MyClass& myClass)
{
if (this != &myClass)
{
destruct();
construct(myClass);
}
return *this;
}
~MyClass()
{
destruct();
}
};
Is this even correct?
And is it a good habit to split the code this way?
One initial comment: the operator= does not start by
destructing, but by constructing. Otherwise, it will leave the
object in an invalid state if the construction terminates via an
exception. Your code is incorrect because of this. (Note that
the necessity to test for self assignment is usually a sign that
the assignment operator is not correct.)
The classical solution for handling this is the swap idiom: you
add a member function swap:
void MyClass:swap( MyClass& other )
{
std::swap( count, other.count );
std::swap( data, other.data );
}
which is guaranteed not to throw. (Here, it just swaps an int
and a pointer, neither of which can throw.) Then you
implement the assignment operator as:
MyClass& MyClass<T>::operator=( MyClass const& other )
{
MyClass tmp( other );
swap( tmp );
return *this;
}
This is simple and straight forward, but any solution in which
all operations which may fail are finished before you start
changing the data is acceptable. For a simple case like your
code, for example:
MyClass& MyClass<T>::operator=( MyClass const& other )
{
T* newData = cloneData( other.data, other.count );
delete data;
count = other.count;
data = newData;
return *this;
}
(where cloneData is a member function which does most of what
your construct does, but returns the pointer, and doesn't
modify anything in this).
EDIT:
Not directly related to your initial question, but generally, in
such cases, you do not want to do a new T[count] in
cloneData (or construct, or whatever). This constructs all
of the T with the default constructor, and then assigns them.
The idiomatic way of doing this is something like:
T*
MyClass<T>::cloneData( T const* other, int count )
{
// ATTENTION! the type is a lie, at least for the moment!
T* results = static_cast<T*>( operator new( count * sizeof(T) ) );
int i = 0;
try {
while ( i != count ) {
new (results + i) T( other[i] );
++ i;
}
} catch (...) {
while ( i != 0 ) {
-- i;
results[i].~T();
}
throw;
}
return results;
}
Most often, this will be done using a separate (private) manager
class:
// Inside MyClass, private:
struct Data
{
T* data;
int count;
Data( int count )
: data( static_cast<T*>( operator new( count * sizeof(T) ) )
, count( 0 )
{
}
~Data()
{
while ( count != 0 ) {
-- count;
(data + count)->~T();
}
}
void swap( Data& other )
{
std::swap( data, other.data );
std::swap( count, other.count );
}
};
Data data;
// Copy constructor
MyClass( MyClass const& other )
: data( other.data.count )
{
while ( data.count != other.data.count ) {
new (data.data + data.count) T( other.date[data.count] );
++ data.count;
}
}
(and of course, the swap idiom for assignment). This allows
multiple count/data pairs without any risk of loosing exception
safety.
I don't see any inherent problem with that, as long as you make sure not to declare construct or destruct virtual.
You might be interested in chapter 2 in Effective C++ (Scott Meyers), which is completely devoted to constructors, copy operators and destructors.
As for exceptions, which your code is not handling as it should, consider items 10 & 11 in More effective C++ (Scott Meyers).
Implement the assignment by first copying the right-hand side and then swapping with that. This way you also get exception safety, which your code above doesn't provide. You could end up with a broken container when construct() fails after destruct() succeeded otherwise, because the member pointer references some deallocated data, and on destruction that will be deallocated again, causing undefined behaviour.
foo&
foo::operator=(foo const& rhs)
{
using std::swap;
foo tmp(rhs);
swap(*this, tmp);
return *this;
}

C++ disallow stack instance but allow new delete

Basically what I want is:
class MyClass{
public:
MyClass() = default;
// what should I do?
}
MyClass mc; // compile time error;
auto pmc = new MyClass; //OK
delete pmc; //OK too
I know I can make it heap-only by hiding constructor (can not new outside of the class now) or hiding destructor (can not delete outside of the class now) or hiding both. What if I don't want to introduce some new named function and just want the good old new and delete? Is it possible (even with hack)?
My "like a smart pointer, but not" idea:
#include <iostream>
class MyClass_ {
private:
/**/ MyClass_( void ) { }
/**/ ~MyClass_( void ) { }
public:
void func( void ) const { std::cout << "Hello" << std::endl; }
friend class MyClass;
} ;
class MyClass {
public:
/**/ MyClass( void ) : p( new MyClass_ ) { }
/**/ ~MyClass( void ) { delete p; }
// Tricky implementation details follow...
// The question in all cases is, who owns the MyClass_ that has been
// allocated on the heap? Do you always allocate a new one, and then
// copy the guts? (That might be expensive!) Do you change ownership?
// Then what about the other MyClass? What does it point to?
// Or do you share ownership? Then you need to ref-count so you don't
// delete too soon. (And this whole thing turns into an ordinary
// shared_ptr<MyClass_>)
/**/ MyClass( const MyClass &o ) { }
/**/ MyClass( MyClass &&o ) { }
MyClass &operator=( const MyClass &o ) { }
MyClass &operator=( MyClass &&o ) { }
MyClass_ * operator->( void ) { return p; }
const MyClass_ * operator->( void ) const { return p; }
private:
MyClass_ *p;
} ;
int
main( int, char ** )
{
MyClass a; // this will be destroyed properly
MyClass *b = new MyClass; // this will leak if you don't delete it
a->func( );
(*b)->func( );
return 0;
}
This is going to sound like not-what-you-want, but surround it in another class. That way you can enforce your storage is allocated off of the heap, and keep such details away from your API user.
A usual way would be to make your constructor private, and add some static member function (you could call it a factory or making function) which returns a pointer.
So your class would look like
class MyClass{
private:
MyClass() = default;
public:
static MyClass* make() { return new MyClass; };
// what should I do?
}
and you'll code:
auto mc = MyClass::make();
elsewhere (instead of new MyClass)
etc. However be aware of the rule of five and consider using (as return type of your MyClass::make) some smart pointer from the <memory> header.
You could also define your own smart pointer class with its own unary operator -> and operator * and your own variadic templates inspired by std::make_shared ...
just want the good old new and delete
In genuine C++11, this is frowned upon and may be considered bad style. You should avoid using explicitly new outside of your library, and adopt some smart pointer way of coding.

c++ move operators class members

I am writting a small wrapper around a library that uses handles.
Basic uses of this library are :
int handle;
createHandle( 1, &handle )
doSomethingWithHandle( handle );
// ...
destroyHandle( handle );
I made a wrapper class following RAII principles:
Handle::Handle()
{
createHandle( 1, &m_handle );
}
Handle::~Handle()
{
if( m_handle!= 0 )
destroyHandle( m_handle );
}
Handle::Handle( Handle&& h ) :
m_handle( h.m_handle )
{
h.m_handle = 0;
}
Handle& Handle::operator=( Handle&& h )
{
m_handle = h.m_handle;
h.m_handle = 0;
return *this;
}
// copy constructor and copy assignment operator are explicitely deleted
It's working, however, a lot a classes depends on those wrappers, which means everytime a class has a Handle member, I have to explicitely write move constructor/move assignment operators:
SomeClass::SomeClass( SomeClass&& s ) :
m_handle( std::move( s.m_handle ) )
{
}
SomeClass& SomeClass::SomeClass( SomeClass&& s )
{
m_handle = std::move( s.m_handle );
return *this;
}
This is, of course, not hard to do, but I wonder if there is a way to avoid that, because thats a lot of redundant code.
If that's not possible, why aren't the move operators not generated by the compiler? Let's take the following lines:
SomeClass a;
m_vector.push_back( a );
In this case, someclass is not copyable so the compiler will have an error because a.m_handle have copy operators deleted. So it means we HAVE to move them. But if we do, doesn't it makes sence that we want to move every members ( if we can't copy them )?
Edit: I just tried something and it seems to work, just declare the move operators using default. This is the way to go I suppose. But the "why" question remains.
Edit2: Another example
class Test
{
public:
Test()
{
m_vec.resize( 10 );
}
Test( const Test& ) = delete;
Test& operator=( const Test& ) = delete;
//Test( Test&& ) = default;
//Test& operator=( Test&& ) = default;
void cout()
{
std::cout << m_vec.size() << std::endl;
}
private:
std::vector< int > m_vec;
};
int main()
{
Test a;
std::vector< Test > v;
v.push_back( std::move( a ) );
v[ 0 ].cout();
}
I have to explicitely write move constructor/move assignment operators:
This is where you are wrong. Either do not write them at all and let the compiler, or =default; them.
SomeClass a;
m_vector.push_back( a );
You did that wrong, it must be:
SomeClass a;
m_vector.push_back( std::move(a) );

Avoid repeating the same code in copy constructor and operator=

In c++ when classes contains dynamically allocated data it is usually reasonable to explicitly define copy constructor, operator= and destructor. But the activity of these special methods overlaps. More specifically operator= usually first does some destruction and then it does coping similar to the one in copy constructor.
My question is how to write this the best way without repeating the same lines of code and without the need for processor to do unnecessary work (like unnecessary copying).
I usually end up with two helping methods. One for construction and one for destruction. The first is called from both copy constructor and operator=. The second is used by destructor and operator=.
Here is the example code:
template <class T>
class MyClass
{
private:
// Data members
int count;
T* data; // Some of them are dynamicly allocated
void construct(const MyClass& myClass)
{
// Code which does deep copy
this->count = myClass.count;
data = new T[count];
try
{
for (int i = 0; i < count; i++)
data[i] = myClass.data[i];
}
catch (...)
{
delete[] data;
throw;
}
}
void destruct()
{
// Dealocate all dynamicly allocated data members
delete[] data;
}
public: MyClass(int count) : count(count)
{
data = new T[count];
}
MyClass(const MyClass& myClass)
{
construct(myClass);
}
MyClass& operator = (const MyClass& myClass)
{
if (this != &myClass)
{
destruct();
construct(myClass);
}
return *this;
}
~MyClass()
{
destruct();
}
};
Is this even correct?
And is it a good habit to split the code this way?
One initial comment: the operator= does not start by
destructing, but by constructing. Otherwise, it will leave the
object in an invalid state if the construction terminates via an
exception. Your code is incorrect because of this. (Note that
the necessity to test for self assignment is usually a sign that
the assignment operator is not correct.)
The classical solution for handling this is the swap idiom: you
add a member function swap:
void MyClass:swap( MyClass& other )
{
std::swap( count, other.count );
std::swap( data, other.data );
}
which is guaranteed not to throw. (Here, it just swaps an int
and a pointer, neither of which can throw.) Then you
implement the assignment operator as:
MyClass& MyClass<T>::operator=( MyClass const& other )
{
MyClass tmp( other );
swap( tmp );
return *this;
}
This is simple and straight forward, but any solution in which
all operations which may fail are finished before you start
changing the data is acceptable. For a simple case like your
code, for example:
MyClass& MyClass<T>::operator=( MyClass const& other )
{
T* newData = cloneData( other.data, other.count );
delete data;
count = other.count;
data = newData;
return *this;
}
(where cloneData is a member function which does most of what
your construct does, but returns the pointer, and doesn't
modify anything in this).
EDIT:
Not directly related to your initial question, but generally, in
such cases, you do not want to do a new T[count] in
cloneData (or construct, or whatever). This constructs all
of the T with the default constructor, and then assigns them.
The idiomatic way of doing this is something like:
T*
MyClass<T>::cloneData( T const* other, int count )
{
// ATTENTION! the type is a lie, at least for the moment!
T* results = static_cast<T*>( operator new( count * sizeof(T) ) );
int i = 0;
try {
while ( i != count ) {
new (results + i) T( other[i] );
++ i;
}
} catch (...) {
while ( i != 0 ) {
-- i;
results[i].~T();
}
throw;
}
return results;
}
Most often, this will be done using a separate (private) manager
class:
// Inside MyClass, private:
struct Data
{
T* data;
int count;
Data( int count )
: data( static_cast<T*>( operator new( count * sizeof(T) ) )
, count( 0 )
{
}
~Data()
{
while ( count != 0 ) {
-- count;
(data + count)->~T();
}
}
void swap( Data& other )
{
std::swap( data, other.data );
std::swap( count, other.count );
}
};
Data data;
// Copy constructor
MyClass( MyClass const& other )
: data( other.data.count )
{
while ( data.count != other.data.count ) {
new (data.data + data.count) T( other.date[data.count] );
++ data.count;
}
}
(and of course, the swap idiom for assignment). This allows
multiple count/data pairs without any risk of loosing exception
safety.
I don't see any inherent problem with that, as long as you make sure not to declare construct or destruct virtual.
You might be interested in chapter 2 in Effective C++ (Scott Meyers), which is completely devoted to constructors, copy operators and destructors.
As for exceptions, which your code is not handling as it should, consider items 10 & 11 in More effective C++ (Scott Meyers).
Implement the assignment by first copying the right-hand side and then swapping with that. This way you also get exception safety, which your code above doesn't provide. You could end up with a broken container when construct() fails after destruct() succeeded otherwise, because the member pointer references some deallocated data, and on destruction that will be deallocated again, causing undefined behaviour.
foo&
foo::operator=(foo const& rhs)
{
using std::swap;
foo tmp(rhs);
swap(*this, tmp);
return *this;
}

Collection of objects of more than one type

Is there any non-awful way to have a collection of objects of more than one type? I'm perfectly happy to derive each type from a common base. I need sensible semantics so the collection can be copied, assigned, and so on.
Obviously, I can't just use a vector or list of the base class. Objects will be sliced and copying won't work at all. Using vectors or lists of pointers or smart pointers works, but you don't get sane copy semantics.
To get sane copy semantics, you need to use something like Boost's ptr_vector. But this requires a painful and error-prone infrastructure. Essentially, you can't just derive a new class from the base class because if it ever goes into the collection, it will not be properly copied.
This seems like such a common thing to do and all the solutions I know of are so awful. It seems like C++ is fundamentally missing a way to create a new instance of an object identical to a given instance -- even if that type has a copy constructor. And making a clone or duplicate function requires careful overloading in every derived class. If you fail to do it when creating a new class derived from the base (or any other class derived from that base) -- boom, your collection breaks.
Is there really no better way?
You can use std::vector<boost::any> to do most of this I think.
#include "boost/any.hpp"
#include <vector>
#include <iostream>
//Simple class so we can see what's going on
class MM {
public:
MM() { std::cout<<"Create # "<<this<<std::endl; }
MM( const MM & o ) { std::cout<<"Copy "<<&o << " -> "<<this<<std::endl; }
~MM() { std::cout<<"Destroy # "<<this<<std::endl; }
};
int main()
{
//Fill a vector with some stuff
std::vector<boost::any> v;
v.push_back(0);
v.push_back(0);
v.push_back(0);
v.push_back(0);
//Overwrite one entry with one of our objects.
v[0] = MM();
std::cout<<"Copying the vector"<<std::endl;
std::vector<boost::any> w;
w = v;
std::cout<<"Done"<<std::endl;
}
For which I get the output:
Create # 0xbffff6ae
Copy 0xbffff6ae -> 0x100154
Destroy # 0xbffff6ae
Copying the vector
Copy 0x100154 -> 0x100194
Done
Destroy # 0x100194
Destroy # 0x100154
Which is what I expect to see.
EDIT:
In line with your requirements to be able to treat members as some common base-type you'll need something very similar to boost::any, which thankfully is a relatively simple class.
template<typename BASE>
class any_with_base
{
// ... Members as for boost::any
class placeholder
{
virtual BASE * as_base() = 0;
//Other members as in boost::any::placeholder
};
template<typename ValueType>
class holder : public placeholder
{
virtual BASE * as_base() { return (BASE*)&held; }
//Other members as in boost::any::holder<T>
};
BASE* as_base() { return content?content->as_base():0; }
}
Now you should be able to do this:
vector< any_with_base<Base> > v;
v.push_back( DerivedA() );
v.push_back( DerivedB() );
v[0].as_base()->base_fn();
v[1].as_base()->base_fn();
any_cast<DerivedA>(v[0])->only_in_a();
I actually dislike the syntax of any_cast and would use this opportunity to add an "as" member function.. so that I could write the last line as:
v[0].as<DerivedA>()->only_in_a();
Alright, to follow up my comment, there is a way to do this without using boost::any that should offer superior performance in most cases, but it's admittedly a bit more involved. My solution combines two ideas: the use of a holder class that elides the type of its contents, and lightweight custom RTTI. We give the holder class meaningful copy and assignment semantics and we use containers of holders to manage the collection of objects. We use our lightweight RTTI to discover the true types of the objects when necessary. Here's some code to demonstrate what I'm proposing:
#include <vector>
#include <cassert>
#include <iostream>
#include <boost/cast.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/static_assert.hpp>
/// This template makes it possible to enforce the invariant that every type in a
/// hierarchy defines the id( ) function, which is necessary for our RTTI. Using
/// a static assertion, we can force a compile error if a type doesn't provide id( ).
template< typename T >
struct provides_id {
typedef char one;
typedef long two;
template< typename U, std::string const &(U::*)( ) const = &U::id >
struct id_detector { };
template< typename U > static one test( id_detector< U > * );
template< typename U > static two test( ... );
enum { value = sizeof(test<T>(0)) == sizeof(one) };
};
/// Base class for the holder. It elides the true type of the object that it holds,
/// providing access only through the base class interface. Since there is only one
/// derived type, there is no risk of forgetting to define the clone() function.
template< typename T >
struct holder_impl_base {
virtual ~holder_impl_base( ) { }
virtual T *as_base( ) = 0;
virtual T const *as_base( ) const = 0;
virtual holder_impl_base *clone( ) const = 0;
};
/// The one and only implementation of the holder_impl_base interface. It stores
/// a derived type instance and provides access to it through the base class interface.
/// Note the use of static assert to force the derived type to define the id( )
/// function that we use to recover the instance's true type.
template< typename T, typename U >
struct holder_impl : public holder_impl_base< T > {
BOOST_STATIC_ASSERT(( provides_id< U >::value ));
holder_impl( U const &p_data )
: m_data( p_data )
{ }
virtual holder_impl *clone( ) const {
return new holder_impl( *this );
}
virtual T *as_base( ) {
return &m_data;
}
virtual T const *as_base( ) const {
return &m_data;
}
private:
U m_data;
};
/// The holder that we actually use in our code. It can be constructed from an instance
/// of any type that derives from T and it uses a holder_impl to elide the type of the
/// instance. It provides meaningful copy and assignment semantics that we are looking
/// for.
template< typename T >
struct holder {
template< typename U >
holder( U const &p_data )
: m_impl( new holder_impl< T, U >( p_data ))
{ }
holder( holder const &p_other )
: m_impl( p_other.m_impl -> clone( ))
{ }
template< typename U >
holder &operator = ( U const &p_data ) {
m_impl.reset( new holder_impl< T, U >( p_data ));
return *this;
}
holder &operator = ( holder const &p_other ) {
if( this != &p_other ) {
m_impl.reset( p_other.m_impl -> clone( ));
}
return *this;
}
T *as_base( ) {
return m_impl -> as_base( );
}
T const *as_base( ) const {
return m_impl -> as_base( );
}
/// The next two functions are what we use to cast elements to their "true" types.
/// They use our custom RTTI (which is guaranteed to be defined due to our static
/// assertion) to check if the "true" type of the object in a holder is the same as
/// as the template argument. If so, they return a pointer to the object; otherwise
/// they return NULL.
template< typename U >
U *as( ) {
T *base = as_base( );
if( base -> id( ) == U::static_id( )) {
return boost::polymorphic_downcast< U * >( base );
}
return 0;
}
template< typename U >
U const *as( ) const {
T *base = as_base( );
if( base -> id( ) == U::static_id( )) {
return boost::polymorphic_downcast< U const * >( base );
}
return 0;
}
private:
boost::scoped_ptr< holder_impl_base< T > > m_impl;
};
/// A base type and a couple derived types to demonstrate the technique.
struct base {
virtual ~base( )
{ }
virtual std::string const &id( ) const = 0;
};
struct derived1 : public base {
std::string const &id( ) const {
return c_id;
}
static std::string const &static_id( ) {
return c_id;
}
private:
static std::string const c_id;
};
std::string const derived1::c_id( "derived1" );
struct derived2 : public base {
std::string const &id( ) const {
return c_id;
}
static std::string const &static_id( ) {
return c_id;
}
private:
static std::string const c_id;
};
std::string const derived2::c_id( "derived2" );
/// A program to demonstrate that the technique works as advertised.
int main( ) {
std::vector< holder< base > > vector1;
vector1.push_back( derived1( ));
vector1.push_back( derived2( ));
std::vector< holder< base > > vector2 = vector1;
/// We see that we have true copies!
assert( vector1[0].as_base( ) != vector2[0].as_base( ));
assert( vector1[1].as_base( ) != vector2[0].as_base( ));
/// Easy assignment of container elements to new instances!
vector2[0] = derived2( );
vector2[1] = derived1( );
// Recovery of the "true" types!
std::vector< holder< base > >::iterator l_itr = vector1.begin( );
std::vector< holder< base > >::iterator l_end = vector1.end ( );
for( ; l_itr != l_end; ++l_itr ) {
if( derived1 *ptr = l_itr -> as< derived1 >( )) {
std::cout << ptr -> static_id( ) << std::endl;
}
else if( derived2 *ptr = l_itr -> as< derived2 >( )) {
std::cout << ptr -> static_id( ) << std::endl;
}
}
}
And here's the output:
derived1
derived2