I have a class Bar which stores objects derived from BarItem:
#include <list>
#include <memory>
class Bar {
public:
typedef std::shared_ptr<BarItem> item_ptr;
void add_item(item_ptr item) {
items_.push_back(item);
}
private:
std::list<item_ptr> items_;
};
I have another class Note which is a subclass of BarItem. Currently to add a copy of a Note object I am doing:
Bar my_bar;
Note my_note;
my_bar.add_item(Bar::item_ptr(new Note(my_note)));
Which is a bit ugly; I would like to know if there is a better way or a way to automate this?
You can't actually avoid the copy (in C++11 you can make it a move), but you can "automate" it so you save a few keystrokes by overloading the add_item function for each type (that may be child of BarItem).
template <class T>
typedef enable_if<is_base_of<BarItem, T>::value,void>::type add_item(const T& item) { /* or T&& */
items_.push_back(item_ptr(new T(item)));
}
You can move that ugly part in the function itself as:
template<typename ItemType>
void add_item(ItemType item) //change the signature
{
items_.push_back(new ItemType(item)); //add the copy!
}
and call it as:
my_bar.add_item(my_note);
Using pointers in containers is one way of reducing the copying of objects. But the way you're handling the creation of the Note object involves making a copy of it via the copy constructor!
Can you avoid having an object and instead have a pointer to the object? You could do this by putting the creation inside a function (factory). That function will take the constructor's arguments, new the object and return a smart pointer.
Related
As you know it is not possible to use the std::enable_shared_from_this and shared_from_this() pair from the constructor of an object since a shared_pointer containing the class is not yet in existance. However, I really would like this functionality. I have attempted my own system and it seems to be working OK.
namespace kp
{
template <class T>
void construct_deleter(T *t)
{
if(!t->_construct_pself)
{
t->~T();
}
free(t);
}
template <class T, typename... Params>
std::shared_ptr<T> make_shared(Params&&... args)
{
std::shared_ptr<T> rtn;
T *t = (T *)calloc(1, sizeof(T));
t->_construct_pself = &rtn;
rtn.reset(t, construct_deleter<T>);
t = new(t) T(std::forward<Params>(args)...);
t->_construct_pself = NULL;
t->_construct_self = rtn;
return rtn;
}
template <class T>
class enable_shared_from_this
{
public:
std::shared_ptr<T> *_construct_pself;
std::weak_ptr<T> _construct_self;
std::shared_ptr<T> shared_from_this()
{
if(_construct_pself)
{
return *_construct_pself;
}
else
{
return _construct_self.lock();
}
}
};
}
Can anyone spot any flaws in this logic? I basically use placement new to assign a pointer to the shared_ptr inside the class before the constructor calls.
As it stands I can use it as so:
std::shared_ptr<Employee> emp = kp::make_shared<Employee>("Karsten", 30);
and in the Employee constructor:
Employee::Employee(std::string name, int age)
{
Dept::addEmployee(shared_from_this());
}
Before I commit this to a relatively large codebase, I would really appreciate some ideas or feedback from you guys.
Thanks!
I know it's been a while but that might be useful to someone with the same issue : the main problem will happen if you attempt to inherit from a class inheriting your enable_shared_from_this.
Especially with this line :
t->_construct_pself = &rtn;
If you have let's say :
class Object : public kp::enable_shared_from_this<Object> {
};
class Component : public Object {
};
Then the compiler won't be able to cast std::shared_ptr<Component>* to std::shared_ptr<Object>* as for the compiler those types are not related even though Component inherits Object.
The easiest solution I see would be to turn _construct_pself to void* like so :
template <class T>
class enable_shared_from_this
{
public:
void* _construct_pself{ nullptr };
std::weak_ptr<T> _construct_self;
std::shared_ptr<T> shared_from_this() const
{
if (_construct_pself)
{
return *static_cast<std::shared_ptr<T>*>(_construct_pself);
}
else
{
return _construct_self.lock();
}
}
};
And then do
t->_construct_pself = static_cast<void*>(&rtn);
It's not very sexy and might make other issues arise but it seems to be working...
[EDIT] There is a slightly better and more "C++" alternative, sorry for not thinking about it right away, just do :
t->_construct_pself = reinterpret_cast<decltype(t->_construct_pself)>(&rtn);
[EDIT2] Make shared_from_this const as it does not change anything in the class
[EDIT3] Found an other issue : If you use a copy constructor via make_shared and use operator= inside the constructor before shared_from_this, shared_from_this will return the address of copied object, not of the object's copy. Only solution I see is to define empty copy constructor and assignment operator for enable_shared_from_this and explicitly call the copy constructor from inheriting classes everytime needed... Either that or MAKE SURE you NEVER call operator= before shared_from_this inside your copy constructor.
I think there is a semantically problem with using shared_from_this() inside the constructor.
The issue is when an exception is being thrown there is no valid object, but you already have setup a shared pointer to it. e.g.:
Employee::Employee(std::string name, int age)
{
Dept::addEmployee(shared_from_this());
if (...) throw std::runtime_error("...");
}
Now Dept will have a pointer to this object, which wasn't successfully created.
Use of shared_from_this() in a constructor should be a code smell, even if it worked, because it is a sign of a possible circular dependency and/or use of a pointer to an incomplete object.
One typically calls shared_from_this() to pass a smart pointer to this object to another object. Doing this during construction would mean that "this" class depends on another component, which depends on "this" class.
Even in the (arguably) valid use case of an object self-registering at some other component, one would be registering an object that is not yet fully constructed, which is a recipe for problems, as pointed out, for example, in this answer.
The solution I would recommend is therefore to analyze the code or design and look for possible circular dependencies, then break that cycle.
In the "self-registering object" use case, consider moving the responsibility of registration somewhere else, for example, to the same place where the object is being instantiated. If necessary, use a "create" function or factory rather than direct construction.
This question already has answers here:
How can I safely (and easily) count *all* instances of a class within my program?
(2 answers)
Closed 7 years ago.
I want to call all object exist in a project. how can i do that?
Class1 Abc;
Class1 Xyz;
Class1 asd[100];
for each (Class1 k in ???)
{
k.dosomething();
}
C++ has no notion of "project", so there's no formally correct answer as to how to call a method on all objects of a given class in a project.
Possibly you mean in a "program".
One way is to register a pointer to each object in a global set of such object pointers. A main problem with that is that ideally it's the constructor that has to do the registering job, and the constructor doesn't know if this object will end up as const. And so you can inadvertently end up calling a modifier method on a const object.
One (limited) solution is to have do_something as const method, when that's practical.
Another (general but more complex) solution is to restrict creation of objects of that class to factory functions, because a factory function can register an object after it's turned const after successful construction.
C++ doesn't have type introspection, so it's impossible.
You can solve it by storing all object of Class1 in a container, and then iterate over that. For example, you could have a static member variable, a vector, and in the constructor you simply add this to the vector. It only works for that single class though, and there's no good or standard way to generalize it.
There are libraries that can add simple type introspection functionality, but it always requires you to add extra code to your classes, and usage of macros.
C++ language does not support this but you can implement it as an object pool pattern. This pattern is especially useful for efficient memory management and economical usage of memory and other resources in tightly constrained environments, where even small performance gains are of vital importance.
You can use Curiously recurring template patterns to inherit from a class which updates a container including all the classes for you.
#include <iostream>
#include <unordered_set>
template <typename T>
class IterableType{
public:
std::unordered_set<T const*>& allClasses(){
return classes_;
}
protected:
IterableType(){
IterableType<T>::classes_.insert(static_cast<T*>(this));
}
IterableType(const IterableType<T>& t){
IterableType<T>::classes_.insert(static_cast<T*>(this));
}
IterableType(const IterableType<T>&& t){
IterableType<T>::classes_.insert(static_cast<T*>(this));
}
IterableType<T>& operator=(const IterableType<T>& t){
return *this;
}
IterableType<T>& operator=(const IterableType<T>&& t){
return *this;
}
~IterableType(){
IterableType<T>::classes_.erase(static_cast<T*>(this));
}
private:
static std::unordered_set<T const*> classes_;
};
template <typename T>
std::unordered_set<T const*> IterableType<T>::classes_;
The constructor and destructor are protected as they are only supposed to be called from the derived classes. As the set is declared with const members it will never allow to modify const classes. However, if you want to modify them in them while iterating you need to use const_cast or remove the const from declaration. But as said these would allow the modification of const objects.
To use this you just inherit from this class using the child class as a template argument.
class Class1:public IterableType<Class1>{
public:
Class1(int n):n_(n)
{}
void print() const{
std::cout << n_ << std::endl;
}
private:
int n_;
};
int main(){
Class1 a(3),b(7),c(8);
for (auto i:a.allClasses()){
i->print();
}
return 0;
}
Edit: Implemented copy and move constructors and made the set const
I am trying to write a class that I can store and use type information in without the need for a template parameter.
I want to write something like this:
class Example
{
public:
template<typename T>
Example(T* ptr)
: ptr(ptr)
{
// typedef T EnclosedType; I want this be a avaialable at the class level.
}
void operator()()
{
if(ptr == NULL)
return;
(*(EnclosedType*)ptr)(); // so i can cast the pointer and call the () operator if the class has one.
}
private:
void* ptr;
}
I am not asking how to write an is_functor() class.
I want to know how to get type information in a constructor and store it at the class level. If that is impossible, a different solution to this would be appreciated.
I consider this as a good and valid question, however, there is no general solution beside using a template parameter at the class level. What you tried to achieve in your question -- using a typedef inside a function and then access this in the whole class -- is not possible.
Type erasure
Only if you impose certain restrictions onto your constructor parameters, there are some alternatives. In this respect, here is an example of type erasure where the operator() of some given object is stored inside a std::function<void()> variable.
struct A
{
template<typename T>
A(T const& t) : f (std::bind(&T::operator(), t)) {}
void operator()() const
{
f();
}
std::function<void()> f;
};
struct B
{
void operator()() const
{
std::cout<<"hello"<<std::endl;
}
};
int main()
{
A(B{}).operator()(); //prints "hello"
}
DEMO
Note, however, the assumptions underlying this approach: one assumes that all passed objects have an operator of a given signature (here void operator()) which is stored inside a std::function<void()> (with respect to storing the member-function, see here).
Inheritance
In a sense, type erasure is thus like "inheriting without a base class" -- one could instead use a common base class for all constructor parameter classes with a virtual bracket operator, and then pass a base class pointer to your constructor.
struct A_parameter_base
{
void operator()() const = 0;
};
struct B : public A_parameter_base
{
void operator()() const { std::cout<<"hello"<<std::endl; }
};
struct A
{
A(std::shared_ptr<A_parameter_base> _p) : p(_p) {}
void operator()()
{
p->operator();
}
std::shared_ptr<A_parameter_base> p;
}
That is similar to the code in your question, only that it does not use a void-pointer but a pointer to a specific base class.
Both approaches, type erasure and inheritance, are similar in their applications, but type erasure might be more convenient as one gets rid of a common base class. However, the inheritance approach has the further advantage that you can restore the original object via multiple dispatch
This also shows the limitations of both approaches. If your operator would not be void but instead would return some unknown varying type, you cannot use the above approach but have to use templates. The inheritance parallel is: you cannot have a virtual function template.
The practical answer is to store either a copy of your class, or a std::ref wrapped pseudo-reference to your class, in a std::function<void()>.
std::function type erases things it stores down to 3 concepts: copy, destroy and invoke with a fixed signature. (also, cast-back-to-original-type and typeid, more obscurely)
What it does is it remembers, at construction, how to do these operations to the passed in type, and stores a copy in a way it can perform those operations on it, then forgets everything else about the type.
You cannot remember everything about a type this way. But almost any operation with a fixed signature, or which can be intermediaried via a fixed signature operation, can be type erased down to.
The first typical way to do this are to create a private pure interface with those operations, then create a template implementation (templated on the type passed to the ctor) that implements each operation for that particular type. The class that does the type erasure then stores a (smart) pointer to the private interface, and forwards its public operations to it.
A second typical way is to store a void*, or a buffer of char, and a set of pointers to functions that implement the operations. The pointers to functions can be either stored locally in the type erasing class, or stored in a helper struct that is created statically for each type erased, and a pointer to the helper struct is stored in the type erasing class. The first way to store the function pointers is like C-style object properties: the second is like a manual vtable.
In any case, the function pointers usually take one (or more) void* and know how to cast them back to the right type. They are created in the ctor that knows the type, either as instances of a template function, or as local stateless lambdas, or the same indirectly.
You could even do a hybrid of the two: static pimpl instance pointers taking a void* or whatever.
Often using std::function is enough, manually writing type erasure is hard to get right compared to using std::function.
Another version to the first two answers we have here - that's closer to your current code:
class A{
public:
virtual void operator()=0;
};
template<class T>
class B: public A{
public:
B(T*t):ptr(t){}
virtual void operator(){(*ptr)();}
T*ptr;
};
class Example
{
public:
template<typename T>
Example(T* ptr)
: a(new B<T>(ptr))
{
// typedef T EnclosedType; I want this be a avaialable at the class level.
}
void operator()()
{
if(!a)
return;
(*a)();
}
private:
std::unique_ptr<A> a;
}
I need to store multiple types of a template class in a single vector.
Eg, for:
template <typename T>
class templateClass{
bool someFunction();
};
I need one vector that will store all of:
templateClass<int> t1;
templateClass<char> t2;
templateClass<std::string> t3;
etc
As far as I know this is not possible, if it is could someone say how?
If it isn't possible could someone explain how to make the following work?
As a work around I tried to use a base, non template class and inherit the template class from it.
class templateInterface{
virtual bool someFunction() = 0;
};
template <typename T>
class templateClass : public templateInterface{
bool someFunction();
};
I then created a vector to store the base "templateInterface" class:
std::vector<templateInterface> v;
templateClass<int> t;
v.push_back(t);
This produced the following error:
error: cannot allocate an object of abstract type 'templateInterface'
note: because the following virtual functions are pure within 'templateInterface'
note: virtual bool templateInterface::someFunction()
To fix this error I made the function in templateInterface not a pure virtual by providing a function body, this compiled but when calling the function the overide is not used, but instead the body in the virtual function.
Eg:
class templateInterface{
virtual bool someFunction() {return true;}
};
template <typename T>
class templateClass : public templateInterface{
bool someFunction() {return false;}
};
std::vector<templateInterface> v;
templateClass<int> i;
v.push_back(i);
v[0].someFunction(); //This returns true, and does not use the code in the 'templateClass' function body
Is there any way to fix this so that the overridden function is used, or is there another workaround to store multiple template types in a single vector?
Why your code doesn't work:
Calling a virtual function on a value doesn't use polymorphism. It calls the function which is defined for the type of this exact symbol as seen by the compiler, not the runtime type. When you insert sub types into a vector of the base type, your values will be converted into the base type ("type slicing"), which is not what you want. Calling functions on them will now call the function as defined for the base type, since not it is of that type.
How to fix this?
The same problem can be reproduced with this code snippet:
templateInterface x = templateClass<int>(); // Type slicing takes place!
x.someFunction(); // -> templateInterface::someFunction() is called!
Polymorphism only works on a pointer or reference type. It will then use the runtime type of the object behind the pointer / reference to decide which implementation to call (by using it's vtable).
Converting pointers is totally "safe" with regard to type slicing. Your actual values won't be converted at all and polymorphism will work as expected.
Example, analogous to the code snippet above:
templateInterface *x = new templateClass<int>(); // No type slicing takes place
x->someFunction(); // -> templateClass<int>::someFunction() is called!
delete x; // Don't forget to destroy your objects.
What about vectors?
So you have to adopt these changes in your code. You can simply store pointers to actual types in the vector, instead of storing the values directly.
When working with pointers you also have to care about deleting your allocated objects. For this you can use smart pointers which care about deletion automatically. unique_ptr is one such smart pointer type. It deletes the pointee whenever it goes out of scope ("unique ownership" - the scope being the owner). Assuming the lifetime of your objects is bound to the scope this is what you should use:
std::vector<std::unique_ptr<templateInterface>> v;
templateClass<int> *i = new templateClass<int>(); // create new object
v.push_back(std::unique_ptr<templateInterface>(i)); // put it in the vector
v.emplace_back(new templateClass<int>()); // "direct" alternative
Then, call a virtual function on one of these elements with the following syntax:
v[0]->someFunction();
Make sure you make all functions virtual which should be possible to be overridden by subclasses. Otherwise their overridden version will not be called. But since you already introduced an "interface", I'm sure you are working with abstract functions.
Alternative approaches:
Alternative ways to do what you want is to use a variant type in the vector. There are some implementations of variant types, the Boost.Variant being a very popular one. This approach is especially nice if you don't have a type hierarchy (for example when you store primitive types). You would then use a vector type like std::vector<boost::variant<int, char, bool>>
Polymorphism only works through pointers or references. You'll
need the non-template base. Beyond that, you'll need to decide
where the actual objects in container will live. If they're all
static objects (with sufficient lifetime), just using
a std::vector<TemplateInterface*>, and inserting with
v.push_back(&t1);, etc., should do the trick. Otherwise,
you'll probably want to support cloning, and keep clones in the
vector: preferably with Boost pointer containers, but
std::shared_ptr can be used as well.
The solutions given so far are fine though be aware that in case you were returning the template type other than bool in your example , none of these would help as the vtable slots would not be able to be measured before hand. There are actually limits , from a design point of view , for using a template oriented polymorphic solution.
Solution nr. 1
This solution inspired by Sean Parent's C++ Seasoning talk. I highly recommend to check it out on youtube. My solution simplified a bit and the key is to store object in method itself.
One method only
Create a class that will invoke method of stored object.
struct object {
template <class T>
object(T t)
: someFunction([t = std::move(t)]() { return t.someFunction(); })
{ }
std::function<bool()> someFunction;
};
Then use it like this
std::vector<object> v;
// Add classes that has 'bool someFunction()' method
v.emplace_back(someClass());
v.emplace_back(someOtherClass());
// Test our vector
for (auto& x : v)
std::cout << x.someFunction() << std::endl;
Several methods
For several methods use shared pointer to share object between methods
struct object {
template <class T>
object(T&& t) {
auto ptr = std::make_shared<std::remove_reference_t<T>>(std::forward<T>(t));
someFunction = [ptr]() { return ptr->someFunction(); };
someOtherFunction = [ptr](int x) { ptr->someOtherFunction(x); };
}
std::function<bool()> someFunction;
std::function<void(int)> someOtherFunction;
};
Other types
Primitive types (such as int, float, const char*) or classes (std::string etc.) may be wrapped in the same way as object class do but behave differently. For example:
struct otherType {
template <class T>
otherType(T t)
: someFunction([t = std::move(t)]() {
// Return something different
return true;
})
{ }
std::function<bool()> someFunction;
};
So now it is possible to add types that does not have someFunction method.
v.emplace_back(otherType(17)); // Adding an int
v.emplace_back(otherType("test")); // A string
Solution nr. 2
After some thoughts what we basically done in first solution is created array of callable functions. So why not just do the following instead.
// Example class with method we want to put in array
struct myclass {
void draw() const {
std::cout << "myclass" << std::endl;
}
};
// All other type's behaviour
template <class T>
void draw(const T& x) {
std::cout << typeid(T).name() << ": " << x << std::endl;
}
int main()
{
myclass x;
int y = 17;
std::vector<std::function<void()>> v;
v.emplace_back(std::bind(&myclass::draw, &x));
v.emplace_back(std::bind(draw<int>, y));
for (auto& fn : v)
fn();
}
Conclusion
Solution nr. 1 is definitely an interesting method that does not require inheritance nor virtual functions. And can be used to other stuff where you need to store a template argument to be used later.
Solution nr. 2, on the other hand, is simpler, more flexible and probably a better choice here.
If you're looking at a container to store multiple types, then you should explore boost variant from the popular boost library.
I'm creating a new class that inherits queue from the STL library. The only addition to the class is a vector. This vector will have the same size of the queue and it will store some integer values that will correspond to each objects in the queue.
Now, I want to override pop() and push(), but I simply want to add more functionality to the parent's class methods.
ex. When pop() is called on the queue object, I also want pop an object from the vector. When push() is called on the queue object, I also want insert a new object into the vector.
How do I do that???
#include <iostream>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
template <typename type>
class CPU_Q : public queue<type>
{
public:
vector<int> CPU_TIME;
void increaseTime()
{
for(int ndx = 0; ndx < CPU_TIME.size(); ndx++)
{
CPU_TIME[ndx]++;
}
}
void push(type insertMe)
{
//This is what I want to do
super::push(); // or queue::push(); maybe?
CPU_TIME.push_back(0);
}
void pop()
{
//Something very similar to push()
}
}
Many Many thanks in advance
-Tri
You asked about:
void push(type insertMe){
//This is what I want to do
super::push(); // or queue::push(); maybe?
CPU_TIME.push_back(0);
}
That would be more like:
void push(type insertMe) {
queue<type>::push(insertMe);
CPU_TIME.push_back(0);
}
Except you probably want to accept the parameter by const reference:
void push(type const &insertme) {
queue<type>::push(insertMe);
CPU_TIME.push_back(0);
}
That said, the standard container classes aren't really designed for inheritance (e.g. they don't have a virtual dtors), so you'll have to be careful with this -- e.g. when you destroy it, you'll need the static type to be the derived type; you'll get undefined behavior if (for example) you destroy one via a pointer to the base class.
STL queue class in not intended to be extended using inheritance. Look here for more information on that. Besides that std::queue has more than one template argument. Instead of inheriting you could just use std::queue as a member of your template class CPU_Q as follows:
template<typename T>
class CPU_Q
{
std::queue<T> q;
public:
void push( T val )
{
q.push( val );
// additional work
}
};
Simple answer is that it is not possible. STL container classes are not designed to be inherited. Their destructor is not virtual to start. If you really want to do something like this then write a new class which 'contains' the queue and vector , and use this class everywhere. BTW as a side note, there is no super keyword in C++ unlike Java. If you want to call base class method use BaseClassName::methodName();
Unless your new class has a is-a relationship with std::queue, I would strongly consider encapsulating the queue and vector, and providing methods that forward to the appropriate std::queue/std::vector methods, in the order you want them to be called.
Also, if you want this new class to be compatible with standard algorithms, you will have to implement a begin() and end() method that return an iterator type capable of walking your data structure; you may be able to use the existing methods on std::queue/std::vector to accomplish this though.