I have a boost::ptr_map which stores abstract base class (e.g. VectorWrapperBase) as values and this allows me to map strings to vectors of different types.
boost::ptr_map<std::string, VectorWrapperBase> memory_map;
//...
memory_map.insert(str_key, new VectorWrapper<T>());
This appears to work. However, when I have memory_map as a member of another class and attempt to store that class in an std::map, compilation fails.
class AgentMemory {
//...
private:
boost::ptr_map<std::string, VectorWrapperBase> memory_map;
};
std::map<std::string, AgentMemory> agent_map;
//...
agent_map.insert(std::pair<std::string, AgentMemory>(agent_name, AgentMemory()));
The last line fails with:
/SOMEPATH/boost_1_48_0/boost/ptr_container/clone_allocator.hpp:34
error: cannot allocate an object of abstract type ‘xyz::VectorWrapperBase’
Being new to C++, this is baffling.
I suspect that error is down to the map insertion copying the AgentMemory object which involves cloning the ptr_map. And since my VectorWrapper objects are not cloneable, the error is raised.
My questions are:
Why am I getting the error? (Are my suspicions even close to what's actually happening?)
How do I address this?
To address the compilation error, I've considered the following, but without much experience with C++ can't decide which is more appropriate:
Remove the pure specifier (= 0) so VectorWrapperBase is no longer abstract
This feels like a hack since VectorWrapperBase should never be instantiated
Make the VectorWrappers cloneable
This seems to work, but in my use case only empty containers are assigned to the top-level map so VectorWrappers within the inner ptr_map need never be cloned. The cloneability would therefore be there just to appease the compiler and does not reflect the actual usage.
Forget ptr_map and use a std::map and shared_ptr instead.
I'm less keen on this solution as I would like the lifetime of the vector wrappers to be linked to that of the map. I'm also a little concerned (perhaps unnecessarily so?) about the potential overheads of extensive use of shared_ptr in a heavily multi-threaded application.
The statement
agent_map.insert(std::pair<std::string, AgentMemory>(agent_name, AgentMemory()));
will call the default constructor of AgentMemory, which in turn will call the default constructor of boost::ptr_map<std::string, VectorWrapperBase>, which will try to call the non-existent constructor for the abstract base class VectorWrapperBase.
So you have to make sure that every constructor of types wrapping or inheriting VectorWrapperBase should always construct a concrete derived class. In your case, option 3 (a map of shared pointers to derived classes) could be sensible, but that depends on the larger context of your code.
Related
suppose I have three class like these:
class base {
//some data
method();
};
class sub1 : base {
//some data
//overrides base method
method();
};
class sub2: base {
//some data
//overrides base methods
method();
};
How can I create a array mixed with sub1 and sub2? then calling subclass method with base?
Ok, let's sort this out. First of all, you probably meant virtual method();, probably with a return type, maybe with parameters. Without virtual, base class pointers and references won't know about the overridden method. Second, make the destructor virtual. Do this until you know why you need to (delete (base*) new derived;) - then keep doing this until all your neighbourhood knows why you need to. Third, the sad thing is, all std. C++ containers are homogeneous (non-std. heterogeneous container-like objects in Boost exist), thus you need to find an object that's common and that's somehow able to handle these types. Common choices are:
Common base class pointer, in your case, base*. This conventionally owns the objects and is manually (de)allocated (that is, you need to call new and delete). This is the most common choice. You might try smart pointers later, but let's get the basics first.
Common base class reference, in your case, base&. Common convention is that this doesn't own the object (albeit this is not a language restriction), thus it's mainly used for referring to objects that are stored in another container. Since you need to store them somewhere, I wouldn't opt for this now, but it might come handy later.
std::variant<> (or boost::variant<>), this is a discriminated union, that is, a class that stores one and only one of the listed items and knows which one it stores. You don't need a common base class, but even if you have one, it's cool because it tends to store objects locally, thus might be faster when you have enough cache.
union, which is like variant, but does not know the type being stored. Local storage is guaranteed, as well as UB if you write one field and read another
Compiler-specific solutions. If you know that your classes are of the same size (in this case, they are) and you know for sure that you have untyped memory, then you might store the base class and it'll 'just work', provided you always take the address and -> operator. Note that this is UB squared, I just list this because you'll likely encounter similar code. Also note that simply having a union does not remove UB in this case - until we have access to virtual table pointer, this can only be done by manually handling virtual functions.
While going through a very good book on templates in C++, I came across an explanation on alternative to templates that I don't understand:
These are bad alternatives to templates in C++
You can write general code for a common base type such as Object or void*.
Reason : If you write general code for a common base class you
lose the benefit of type checking. In addition, classes may be
required to be derived from special base classes, which makes it more
difficult to maintain your code.
Can someone explain this with a code example?
It's not the concept of a common base type that's bad. It's the use of a "Object class" that everything has to be derived from, or worse, writing code that takes void* and then, making assumptions about what the pointer points to, typecasts to a pointer to some other type and hopes for the best. This is best exemplified with containers.
The right way to implement container methods is with templates. For example:
template<typename T> void List<T>::append(const T& obj);
Object class
In the case of an Object base class, what that means is that anything you put in the container must be derived from Object, because all the container methods use Object* for the data in said container. So you get methods like this:
void List::append(Object* obj);
Two bad things here: First, that Object class has to get dragged around with your container wherever you go. Second, it's a horribly generic name and will probably conflict with an Object class from some other library.
Also, your container can never contain types that aren't Object derived directly, including primitive types like int and standard types like std::string. You'd have to "wrap" those types in Object subclasses, and then you'd have to spend time with code to extract the values from those wrapper objects, etc. It's a pain in the rear that you don't need.
void*
So you might think you could use the generic pointer void* instead:
void List::append(void* obj);
But when you do that, there are many things the container may need to do that it can't, because it has no idea what that void* points to:
It can't copy data objects.
It can't compare data objects.
It can't delete data objects.
and so on. (You can avoid these problems in the Object* case with virtual methods, for example declaring something like:
virtual ~Object() {}
virtual Object* clone() const;
virtual int cmp(const Object* rhs) const;
where these methods must be overridden by all subclasses, in your Object base class. But now your Object class isn't very lightweight.)
In both cases, you'd be far better off using a templated type for your container's data type. If you are worried about code bloat and have code in your container that doesn't care about the data type (because it doesn't bother with the data, such as when counting contained elements), you can put that code in a base class and have your templated container class derive from it. But most of the time nobody really cares about this "bloat" because it's much smaller than your available memory.
Type checking discarded
If you write general code for a common base class you lose the benefit of type checking.
Since you've typecast to Object* or void*, type checking went out the window for the most part. (Note: this is somewhat dated, since in some cases you can use Runtime Type Identification (RTTI) and the dynamic_cast operation to perform type checking after the fact, to make sure the object you pulled out of the container is the type you expect. But all the above-mentioned limits still apply, since the container still doesn't know what it's containing.)
The old qsort function used void* pointers for the start of the data and for the parameters to the comparison function. You could easily try to sort an array of double with a comparison function that compared int and wind up with a real mess.
I have a problem which I cannot understand:
Let's Say I have a class System with several member fields, and one of them is of type unordered_map, so when I declare the class in the header file, I write at the beginning of the header #include <unordered_map>.
Now, I have two ways of declaring this field:
1.std::unordered_map<std::string,int> umap;
2.std::unordered_map<std::string,int>* p_umap;
Now in the constructor of the class, if I choose the first option, there is no need to initialize that field in the initializer list since the constructor of class System will call the default constructor for the field umap as part of constructing an instance of type class System.
If I choose the second option, I should initialize the field p_umap in the constructor (in the initialize list) with the operator new and in the destructor, to delete this dynamic allocation.
What is the difference between these two options? If you have a class that one of it's fields is of type unordered_map, how do you declare this field? As a pointer or as a variable of type unordered_map?
In a situation like the one you are describing, it seems like the first option is preferable. Most likely, in fact, the unordered map is intended to be owned by the class it is a data member of. In other words, its lifetime should not be extended beyond the lifetime of the encapsulating class, and the encapsulating class has the responsibility of creating and destroying the unordered map.
While with option 1 all this work is done automatically, with option 2 you would have to take care of it manually (and take care of correct copy-construction, copy-assignment, exception-safety, lack of memory leaks, and so on). Surely you could use smart pointers (e.g. std::unique_ptr<>) to encapsulate this responsibility into a wrapper that would take care of deleting the wrapped object when the smart pointer itself goes out of scope (this idiom is called RAII, which is an acronym for Resource Acquisition Is Initialization).
However, it seems to me like you do not really need a pointer at all here. You have an object whose lifetime is completely bounded by the lifetime of the class that contains it. In these situations, you should just not use pointers and prefer declaring the variable as:
std::unordered_map<std::string, int> umap;
Make it not a pointer until you need to make it a pointer.
Pointers are rife with user error.
For example, you forgot to mention that your class System would also need to implement
System( const Sysytem& )
and
System& operator= ( const System& )
or Bad Behavior will arise when you try to copy your object.
The difference is in how you want to be able to access umap. Pointers can allow for a bit more flexibility, but they obviously add complexity in terms of allocation (stack vs heap, destructors and such). If you use a pointer to umap, you can do some pretty convoluted stuff such as making two System's with the same umap. In the end though, go with KISS unless there's a compelling reason not to.
There is no need to define it as pointer. If you do it, you must also make sure to implement copy constructor and assignment operator, or disable them completely.
If there is no specific reason to make it a pointer (and you don't show any) just make it a normal member variable.
If I understand correctly we have at least two different ways of implementing composition. (The case of implementation with smart pointers is excluded for simplicity. I almost don't use STL and have no desire to learn it.)
Let's have a look at Wikipedia example:
class Car
{
private:
Carburetor* itsCarb;
public:
Car() {itsCarb=new Carburetor();}
virtual ~Car() {delete itsCarb;}
};
So, it's one way - we have a pointer to object as private member.
One can rewrite it to look like this:
class Car
{
private:
Carburetor itsCarb;
};
In that case we have an object itself as private member. (By the way, am I right to call this entity an object from the terminology point of view?)
In the second case it is not obligatory to implicitly call default constructor (if one need to call non-default constructor it's possible to do it in initializer list) and destructor. But it's not a big problem...
And of course in some aspects these two cases differ more appreciably. For example it's forbidden to call non-const methods of Carburetor instance from const methods of Car class in the second case...
Are there any "rules" to decide which one to use? Am I missing something?
In that case we have an object itself as private member. (By the way, calling this entity as object am I write from the terminology point of view?)
Yes you can say "an object" or "an instance" of the class.
You can also talk about including the data member "by value" instead of "by pointer" (because "by pointer" and "by value" is the normal way to talk about passing parameters, therefore I expect people would understand those terms being applied to data members).
Is there any "rules" to decide which one to use? Am I missed something?
If the instance is shared by more than one container, then each container should include it by pointer instead of value; for example if an Employee has a Boss instance, include the Boss by pointer if several Employee instances share the same Boss.
If the lifetime of the data member isn't the same as the lifetime of the container, then include it by pointer: for example if the data member is instantiated after the container, or destroyed before the container, or destroyed-and-recreated during the lifetime of the container, or if it ever makes sense for the data member to be null.
Another time when you must including by pointer (or by reference) instead of by value is when the type of the data member is an abstract base class.
Another reason for including by pointer is that that might allow you to change the implementation of the data member without recompiling the container. For example, if Car and Carburetor were defined in two different DLLs, you might want to include Carburetor by pointer: because then you might be able to change the implementation of the Carburetor by installing a different Carburetor.dll, without rebuilding the Car.dll.
I tend to prefer the first case because the second one requires you to #include Carburettor.h in Car.h.
Since Carburettor is a private member you should not have to include its definition somewhere else than in the actual Car implementation code. The use of the Carburettor class is clearly an implementation detail and external objects that use your Car object should not have to worry about including other non mandatory dependencies. By using a pointer you just need to use a forward declaration of Carburettor in Car.h.
Composition: prefer member when possible. Use a pointer when polymorphism is needed or when a forward declaration is used. Of course, without smart pointer, manual memory management is needed when using pointers.
If Carb has the same lifetime as Car, then the non-pointer form is better, in my opinion. If you have to replace the Carb in Car, then I'd opt for the pointer version.
Generally, the non-pointer version is easier to use and maintain.
But in some cases, you can't use it. For example if the car has multiple carburetors and you wish to put them in an array, and the Carburetor constructor requires an argument: you need to create them via new and thus store them as pointers.
Let's say I have an stl vector containing class type "xx". xx is abstract. I have run into the issue where the compiler won't let me "instantiate" when i do something like the following:
std::vector<xx> victor;
void pusher(xx& thing)
{
victor.push_back(thing);
}
void main()
{
;
}
I assume this is because the copy constructor must be called. I have gotten around this issue by storing xx*'s in the vector rather than xx's. Is there a better solution? What is it?
When you use push_back, you are making a copy of the object and storing it in the vector. As you surmised, this doesn't work since you can't instantiate an abstract class, which is basically what the copy-construction is doing.
Using a pointer is recommended, or one of the many smart-pointer types available in libraries like boost and loki.
To be more Catholic than the Pope (or in this case Steve Guidi) the requirements for objects stored in STL containers are that they are copy-constructable and assignable and an abstract class is neither. So in this case a container of pointers is the way to go.
Another thing to consider in case you decide to fix things by not making the class abstract would be slicing.
std::vector (and the whole STL in general) is designed to store values. If you have an abstract class, you don't intent to manipulate value of this type, but to manipulate pointer or references to it. So have a std::vector of abstract class doesn't make sense. And even if it isn't abstract, it doesn't usually make sense to manipulate class designed to be base classes as value, they usually should be noncopiable (copy constructor and assignment operator declared private and not implemented is the standard trick, inheriting from a suitable class whose lone purpose is to make its descendant non copiable -- boost::noncopyable for instance -- has become fashionanle).