Related
I am required to provide a solution to the following problem:
A class is published as a library and made available to the world. It is designed in a way which does not use the pimpl approach. Two new data members need to be defined in this class. How can these additional data members be added to the class without breaking the ABI? The solution should be a generic approach that can be used to avoid ABI breakages for any class designed, which does not use the pimpl approach.
My first solution was to create a new class which inherits from this previous class and then adding the 2 new members there. Then source code which require these 2 new data members can make use of this newly created class. However, my solution was marked incorrect. I was told that I must repurpose an existing data member for other purposes in a similar approach to pimpl. I did not understand what this really means, as I was not provided with any interfaces of this existing class.
What alternatives are there to pimpl which allow changes to existing classes without breaking the ABI?
My guess would be as follows.
Suppose your class contains a pointer data member, say char* x (the type is not important) that is used for thing unrelated to your planned expansion. Your professor wants you to interpret x as a pointer to another thing:
struct expansion {
char* newX;
int newDataMember1;
double newDataMember2;
};
Now whenever you see x in the old code, replace it with a call to a member function getX():
private:
char*& getX() {
return ((expansion*)x)->newX;
}
You should initialize x in the constructor:
x = (char*)new expansion; // or
MyClass() : x((char*)new expansion)
and free it in the destructor.
Now you have your old x as getX(), and the new data members (write an obvious member function to access them).
Of course you should never ever do anything like that in any real code, which is why I do not discuss smart pointers, exception safety, new style casts and other things that could be remotely considered advanced or good style. Add those to taste. This is not a way to write production code, but purely an exercise to satisfy your professor.
What if you don't have a pointer member in your class? In this case you will have to break some actual C++ rules (in addition to principles of good software design, which went down the drain the moment you started even thinking about this "solution"). Repurpose some integral member instead (note, the C++ standard doesn't guarantee it will work at all, though with most implementations it's OK as long as the size of your member is at least the size of a pointer). Or repurpose more than one member that are adjacent to each other (use reinterpret_cast or placement new to place a pointer there). Or, if your class has a vector of something, use data managed by the vector to store a pointer, again with a cast or placement new hack. Everything goes... as long as you get your professor's approval of course, the C++ standard be damned.
Ok, this is really difficult to confess, but I do have a strong temptation at the moment to inherit from std::vector.
I need about 10 customized algorithms for vector and I want them to be directly members of the vector. But naturally I want also to have the rest of std::vector's interface. Well, my first idea, as a law-abiding citizen, was to have an std::vector member in MyVector class. But then I would have to manually reprovide all of the std::vector's interface. Too much to type. Next, I thought about private inheritance, so that instead of reproviding methods I would write a bunch of using std::vector::member's in the public section. This is tedious too actually.
And here I am, I really do think that I can simply inherit publicly from std::vector, but provide a warning in the documentation that this class should not be used polymorphically. I think most developers are competent enough to understand that this shouldn't be used polymorphically anyway.
Is my decision absolutely unjustifiable? If so, why? Can you provide an alternative which would have the additional members actually members but would not involve retyping all of vector's interface? I doubt it, but if you can, I'll just be happy.
Also, apart from the fact that some idiot can write something like
std::vector<int>* p = new MyVector
is there any other realistic peril in using MyVector? By saying realistic I discard things like imagine a function which takes a pointer to vector ...
Well, I've stated my case. I have sinned. Now it's up to you to forgive me or not :)
Actually, there is nothing wrong with public inheritance of std::vector. If you need this, just do that.
I would suggest doing that only if it is really necessary. Only if you can't do what you want with free functions (e.g. should keep some state).
The problem is that MyVector is a new entity. It means a new C++ developer should know what the hell it is before using it. What's the difference between std::vector and MyVector? Which one is better to use here and there? What if I need to move std::vector to MyVector? May I just use swap() or not?
Do not produce new entities just to make something to look better. These entities (especially, such common) aren't going to live in vacuum. They will live in mixed environment with constantly increased entropy.
The whole STL was designed in such way that algorithms and containers are separate.
This led to a concept of different types of iterators: const iterators, random access iterators, etc.
Therefore I recommend you to accept this convention and design your algorithms in such way that they won't care about what is the container they're working on - and they would only require a specific type of iterator which they'd need to perform their operations.
Also, let me redirect you to some good remarks by Jeff Attwood.
The main reason for not inheriting from std::vector publicly is an absence of a virtual destructor that effectively prevents you from polymorphic use of descendants. In particular, you are not allowed to delete a std::vector<T>* that actually points at a derived object (even if the derived class adds no members), yet the compiler generally can't warn you about it.
Private inheritance is allowed under these conditions. I therefore recommend using private inheritance and forwarding required methods from the parent as shown below.
class AdVector: private std::vector<double>
{
typedef double T;
typedef std::vector<double> vector;
public:
using vector::push_back;
using vector::operator[];
using vector::begin;
using vector::end;
AdVector operator*(const AdVector & ) const;
AdVector operator+(const AdVector & ) const;
AdVector();
virtual ~AdVector();
};
You should first consider refactoring your algorithms to abstract the type of container they are operating on and leave them as free templated functions, as pointed out by majority of answerers. This is usually done by making an algorithm accept a pair of iterators instead of container as arguments.
If you're considering this, you've clearly already slain the language pedants in your office. With them out of the way, why not just do
struct MyVector
{
std::vector<Thingy> v; // public!
void func1( ... ) ; // and so on
}
That will sidestep all the possible blunders that might come out of accidentally upcasting your MyVector class, and you can still access all the vector ops just by adding a little .v .
What are you hoping to accomplish? Just providing some functionality?
The C++ idiomatic way to do this is to just write some free functions that implement the functionality. Chances are you don't really require a std::vector, specifically for the functionality you're implementing, which means you're actually losing out on reusability by trying to inherit from std::vector.
I would strongly advise you to look at the standard library and headers, and meditate on how they work.
I think very few rules should be followed blindly 100% of the time. It sounds like you've given it quite a lot of thought, and are convinced that this is the way to go. So -- unless someone comes up with good specific reasons not to do this -- I think you should go ahead with your plan.
There is no reason to inherit from std::vector unless one wants to make a class that works differently than std::vector, because it handles in its own way the hidden details of std::vector's definition, or unless one has ideological reasons to use the objects of such class in place of std::vector's ones. However, the creators of the standard on C++ did not provide std::vector with any interface (in the form of protected members) that such inherited class could take advantage of in order to improve the vector in a specific way. Indeed, they had no way to think of any specific aspect that might need extension or fine-tune additional implementation, so they did not need to think of providing any such interface for any purpose.
The reasons for the second option can be only ideological, because std::vectors are not polymorphic, and otherwise there is no difference whether you expose std::vector's public interface via public inheritance or via public membership. (Suppose you need to keep some state in your object so you cannot get away with free functions). On a less sound note and from the ideological point of view, it appears that std::vectors are a kind of "simple idea", so any complexity in the form of objects of different possible classes in their place ideologically makes no use.
In practical terms: If you do not have any data members in your derived class, you do not have any problems, not even in polymorphic usage. You only need a virtual destructor if the sizes of the base class and the derived class are different and/or you have virtual functions (which means a v-table).
BUT in theory: From [expr.delete] in the C++0x FCD: In the first alternative (delete object), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined.
But you can derive privately from std::vector without problems.
I have used the following pattern:
class PointVector : private std::vector<PointType>
{
typedef std::vector<PointType> Vector;
...
using Vector::at;
using Vector::clear;
using Vector::iterator;
using Vector::const_iterator;
using Vector::begin;
using Vector::end;
using Vector::cbegin;
using Vector::cend;
using Vector::crbegin;
using Vector::crend;
using Vector::empty;
using Vector::size;
using Vector::reserve;
using Vector::operator[];
using Vector::assign;
using Vector::insert;
using Vector::erase;
using Vector::front;
using Vector::back;
using Vector::push_back;
using Vector::pop_back;
using Vector::resize;
...
If you follow good C++ style, the absence of virtual function is not the problem, but slicing (see https://stackoverflow.com/a/14461532/877329)
Why is absence of virtual functions not the problem? Because a function should not try to delete any pointer it receives, since it does not have an ownership of it. Therefore, if following strict ownership policies, virtual destructors should not be needed. For example, this is always wrong (with or without virtual destructor):
void foo(SomeType* obj)
{
if(obj!=nullptr) //The function prototype only makes sense if parameter is optional
{
obj->doStuff();
}
delete obj;
}
class SpecialSomeType:public SomeType
{
// whatever
};
int main()
{
SpecialSomeType obj;
doStuff(&obj); //Will crash here. But caller does not know that
// ...
}
In contrast, this will always work (with or without virtual destructor):
void foo(SomeType* obj)
{
if(obj!=nullptr) //The function prototype only makes sense if parameter is optional
{
obj->doStuff();
}
}
class SpecialSomeType:public SomeType
{
// whatever
};
int main()
{
SpecialSomeType obj;
doStuff(&obj);
// The correct destructor *will* be called here.
}
If the object is created by a factory, the factory should also return a pointer to a working deleter, which should be used instead of delete, since the factory may use its own heap. The caller can get it form of a share_ptr or unique_ptr. In short, do not delete anything you didn't get directly from new.
Yes it's safe as long as you are careful not to do the things that are not safe... I don't think I've ever seen anyone use a vector with new so in practice you'll likely be fine. However, it's not the common idiom in c++....
Are you able to give more information on what the algorithms are?
Sometimes you end up going down one road with a design and then can't see the other paths you might have taken - the fact that you claim to need to vector with 10 new algorithms rings alarm bells for me - are there really 10 general purpose algorithms that a vector can implement, or are you trying to make an object that is both a general purpose vector AND which contains application specific functions?
I'm certainly not saying that you shouldn't do this, it's just that with the information you've given alarm bells are ringing which makes me think that maybe something is wrong with your abstractions and there is a better way to achieve what you want.
I also inherited from std::vector recently, and found it to be very useful and so far I haven't experienced any problems with it.
My class is a sparse matrix class, meaning that I need to store my matrix elements somewhere, namely in an std::vector. My reason for inheriting was that I was a bit too lazy to write interfaces to all the methods and also I am interfacing the class to Python via SWIG, where there is already good interface code for std::vector. I found it much easier to extend this interface code to my class rather than writing a new one from scratch.
The only problem I can see with the approach is not so much with the non-virtual destructor, but rather some other methods, which I would like to overload, such as push_back(), resize(), insert() etc. Private inheritance could indeed be a good option.
Thanks!
This question is guaranteed to produce breathless pearl-clutching, but in fact there is no defensible reason for avoiding, or "unnecessarily multiplying entities" to avoid, derivation from a Standard container. The simplest, shortest possible expression is clearest, and best.
You do need to exercise all the usual care around any derived type, but there is nothing special about the case of a base from the Standard. Overriding a base member function could be tricky, but that would be unwise to do with any non-virtual base, so there is not much special here. If you were to add a data member, you would need to worry about slicing if the member had to be kept consistent with contents of the base, but again that is the same for any base.
The place where I have found deriving from a standard container particularly useful is to add a single constructor that does precisely the initialization needed, with no chance of confusion or hijacking by other constructors. (I'm looking at you, initialization_list constructors!) Then, you can freely use the resulting object, sliced -- pass it by reference to something expecting the base, move from it to an instance of the base, what have you. There are no edge cases to worry about, unless it would bother you to bind a template argument to the derived class.
A place where this technique will be immediately useful in C++20 is reservation. Where we might have written
std::vector<T> names; names.reserve(1000);
we can say
template<typename C>
struct reserve_in : C {
reserve_in(std::size_t n) { this->reserve(n); }
};
and then have, even as class members,
. . .
reserve_in<std::vector<T>> taken_names{1000}; // 1
std::vector<T> given_names{reserve_in<std::vector<T>>{1000}}; // 2
. . .
(according to preference) and not need to write a constructor just to call reserve() on them.
(The reason that reserve_in, technically, needs to wait for C++20 is that prior Standards don't require the capacity of an empty vector to be preserved across moves. That is acknowledged as an oversight, and can reasonably be expected to be fixed as a defect in time for '20. We can also expect the fix to be, effectively, backdated to previous Standards, because all existing implementations actually do preserve capacity across moves; the Standards just haven't required it. The eager can safely jump the gun -- reserving is almost always just an optimization anyway.)
Some would argue that the case of reserve_in is better served by a free function template:
template<typename C>
auto reserve_in(std::size_t n) { C c; c.reserve(n); return c; }
Such an alternative is certainly viable -- and could even, at times, be infinitesimally faster, because of *RVO. But the choice of derivation or free function should be made on its own merits, and not from baseless (heh!) superstition about deriving from Standard components. In the example use above, only the second form would work with the free function; although outside of class context it could be written a little more concisely:
auto given_names{reserve_in<std::vector<T>>(1000)}; // 2
Here, let me introduce 2 more ways to do want you want. One is another way to wrap std::vector, another is the way to inherit without giving users a chance to break anything:
Let me add another way of wrapping std::vector without writing a lot of function wrappers.
#include <utility> // For std:: forward
struct Derived: protected std::vector<T> {
// Anything...
using underlying_t = std::vector<T>;
auto* get_underlying() noexcept
{
return static_cast<underlying_t*>(this);
}
auto* get_underlying() const noexcept
{
return static_cast<underlying_t*>(this);
}
template <class Ret, class ...Args>
auto apply_to_underlying_class(Ret (*underlying_t::member_f)(Args...), Args &&...args)
{
return (get_underlying()->*member_f)(std::forward<Args>(args)...);
}
};
Inheriting from std::span instead of std::vector and avoid the dtor problem.
I'm currently having a discussion with my teacher about class design and we came to the point of Initialize() functions, which he heavily promotes. Example:
class Foo{
public:
Foo()
{ // acquire light-weight resources only / default initialize
}
virtual void Initialize()
{ // do allocation, acquire heavy-weight resources, load data from disk
}
// optionally provide a Destroy() function
// virtual void Destroy(){ /*...*/ }
};
Everything with optional parameters of course.
Now, he also puts emphasis on extendability and usage in class hierarchies (he's a game developer and his company sells a game engine), with the following arguments (taken verbatim, only translated):
Arguments against constructors:
can't be overridden by derived classes
can't call virtual functions
Arguments for Initialize() functions:
derived class can completely replace initialization code
derived class can do the base class initialization at any time during its own initialization
I have always been taught to do the real initialization directly in the constructor and to not provide such Initialize() functions. That said, I for sure don't have as much experience as he does when it comes to deploying a library / engine, so I thought I'd ask at good ol' SO.
So, what exactly are the arguments for and against such Initialize() functions? Does it depend on the environment where it should be used? If yes, please provide reasonings for library / engine developers or, if you can, even game developer in general.
Edit: I should have mentioned, that such classes will be used as member variables in other classes only, as anything else wouldn't make sense for them. Sorry.
For Initialize: exactly what your teacher says, but in well-designed code you'll probably never need it.
Against: non-standard, may defeat the purpose of a constructor if used spuriously. More importantly: client needs to remember to call Initialize. So, either instances will be in an inconsistent state upon construction, or they need lots of extra bookkeeping to prevent client code from calling anything else:
void Foo::im_a_method()
{
if (!fully_initialized)
throw Unitialized("Foo::im_a_method called before Initialize");
// do actual work
}
The only way to prevent this kind of code is to start using factory functions. So, if you use Initialize in every class, you'll need a factory for every hierarchy.
In other words: don't do this if it's not necessary; always check if the code can be redesigned in terms of standard constructs. And certainly don't add a public Destroy member, that's the destructor's task. Destructors can (and in inheritance situations, must) be virtual anyway.
I"m against 'double initialization' in C++ whatsoever.
Arguments against constructors:
can't be overridden by derived classes
can't call virtual functions
If you have to write such code, it means your design is wrong (e.g. MFC). Design your base class so all the necessary information that can be overridden is passed through the parameters of its constructor, so the derived class can override it like this:
Derived::Derived() : Base(GetSomeParameter())
{
}
This is a terrible, terrible idea. Ask yourself- what's the point of the constructor if you just have to call Initialize() later? If the derived class wants to override the base class, then don't derive.
When the constructor finishes, it should make sense to use the object. If it doesn't, you've done it wrong.
One argument for preferring initialization in the constructor: it makes it easier to ensure that every object has a valid state. Using two-phase initialization, there's a window where the object is ill-formed.
One argument against using the constructor is that the only way of signalling a problem is through throwing an exception; there's no ability to return anything from a constructor.
Another plus for a separate initialization function is that it makes it easier to support multiple constructors with different parameter lists.
As with everything this is really a design decision that should be made with the specific requirements of the problem at hand, rather than making a blanket generalization.
A voice of dissension is in order here.
You might be working in an environment where you have no choice but to separate construction and initialization. Welcome to my world. Don't tell me to find a different environment; I have no choice. The preferred embodiment of the products I create is not in my hands.
Tell me how to initialize some aspects of object B with respect to object C, other aspects with respect to object A; some aspects of object C with respect to object B, other aspects with respect to object A. The next time around the situation may well be reversed. I won't even get into how to initialize object A. The apparently circular initialization dependencies can be resolved, but not by the constructors.
Similar concerns goes for destruction versus shutdown. The object may need to live past shutdown, it may need to be reused for Monte Carlo purposes, and it might need to be restarted from a checkpoint dumped three months ago. Putting all of the deallocation code directly in the destructor is a very bad idea because it leaks.
Forget about the Initialize() function - that is the job of the constructor.
When an object is created, if the construction passed successfully (no exception thrown), the object should be fully initialized.
While I agree with the downsides of doing initialization exclusively in the constructor, I do think that those are actually signs of bad design.
A deriving class should not need to override base class initialization behaviour entirely. This is a design flaw which should be cured, rather than introducing Initialize()-functions as a workaround.
Not calling Initialize may be easy to do accidentally and won't give you a properly constructed object. It also doesn't follow the RAII principle since there are separate steps in constructing/destructing the object: What happens if Initialize fails (how do you deal with the invalid object)?
By forcing default initialization you may end up doing more work than doing initialization in the constructor proper.
Ignoring the RAII implications, which others have adequately covered, a virtual initialization method greatly complicates your design. You can't have any private data, because for the ability to override the initialization routine to be at all useful, the derived object needs access to it. So now the class's invariants are required to be maintained not only by the class, but by every class that inherits from it. Avoiding that sort of burden is part of the point behind inheritance in the first place, and the reason constructors work the way they do with regard to subobject creation.
Others have argued at length against the use of Initialize, I myself see one use: laziness.
For example:
File file("/tmp/xxx");
foo(file);
Now, if foo never uses file (after all), then it's completely unnecessary to try and read it (and would indeed be a waste of resources).
In this situation, I support Lazy Initialization, however it should not rely on the client calling the function, but rather each member function should check if it is necessary to initialize or not. In this example name() does not require it, but encoding() does.
Only use initialize function if you don't have the data available at point of creation.
For example, you're dynamically building a model of data, and the data that determines the object hierarchy must be consumed before the data that describes object parameters.
If you use it, then you should make the constructor private and use factory methods instead that call the initialize() method for you. For example:
class MyClass
{
public:
static std::unique_ptr<MyClass> Create()
{
std::unique_ptr<MyClass> result(new MyClass);
result->initialize();
return result;
}
private:
MyClass();
void initialize();
};
That said, initializer methods are not very elegant, but they can be useful for the exact reasons your teacher said. I would not consider them 'wrong' per se. If your design is good then you probably will never need them. However, real-life code sometimes forces you to make compromises.
Some members simply must have values at construction (e.g. references, const values, objects designed for RAII without default constructors)... they can't be constructed in the initialise() function, and some can't be reassigned then.
So, in general it's not a choice of constructor vs. initialise(), it's a question of whether you'll end up having code split between the two.
Of bases and members that could be initialised later, for the derived class to do it implies they're not private; if you go so far as to make bases/members non-private for the sake of delaying initialisaton you break encapsulation - one of the core principles of OOP. Breaking encapsulation prevents base class developer(s) from reasoning about the invariants the class should protect; they can't develop their code without risking breaking derived classes - which they might not have visibility into.
Other times it's possible but sometimes inefficient if you must default construct a base or member with a value you'll never use, then assign it a different value soon after. The optimiser may help - particularly if both functions are inlined and called in quick succession - but may not.
[constructors] can't be overridden by derived classes
...so you can actually rely on them doing what the base class needs...
[constructors] can't call virtual functions
The CRTP allows derived classes to inject functionality - that's typically a better option than a separate initialise() routine, being faster.
Arguments for Initialize() functions:
derived class can completely replace initialization code
I'd say that's an argument against, as above.
derived class can do the base class initialization at any time during its own initialization
That's flexible but risky - if the base class isn't initialised the derived class could easily end up (due to oversight during the evolution of the code) calling something that relies on that base being initialised and consequently fails at run time.
More generally, there's the question of reliable invocation, usage and error handling. With initialise, client code has to remember to call it with failures evident at runtime not compile time. Issues may be reported using return types instead of exceptions or state, which can sometimes be better.
If initialise() needs to be called to set say a pointer to nullptr or a value safe for the destructor to delete, but some other data member or code throws first, all hell breaks loose.
initialise() also forces the entire class to be non-const in the client code, even if the client just wants to create an initial state and ensure it won't be further modified - basically you've thrown const-correctness out the window.
Code doing things like p_x = new X(values, for, initialisation);, f(X(values, for initialisation), v.push_back(X(values, for initialisation)) won't be possible - forcing verbose and clumsy alternatives.
If a destroy() function is also used, many of the above problems are exacerbated.
Ok, this is really difficult to confess, but I do have a strong temptation at the moment to inherit from std::vector.
I need about 10 customized algorithms for vector and I want them to be directly members of the vector. But naturally I want also to have the rest of std::vector's interface. Well, my first idea, as a law-abiding citizen, was to have an std::vector member in MyVector class. But then I would have to manually reprovide all of the std::vector's interface. Too much to type. Next, I thought about private inheritance, so that instead of reproviding methods I would write a bunch of using std::vector::member's in the public section. This is tedious too actually.
And here I am, I really do think that I can simply inherit publicly from std::vector, but provide a warning in the documentation that this class should not be used polymorphically. I think most developers are competent enough to understand that this shouldn't be used polymorphically anyway.
Is my decision absolutely unjustifiable? If so, why? Can you provide an alternative which would have the additional members actually members but would not involve retyping all of vector's interface? I doubt it, but if you can, I'll just be happy.
Also, apart from the fact that some idiot can write something like
std::vector<int>* p = new MyVector
is there any other realistic peril in using MyVector? By saying realistic I discard things like imagine a function which takes a pointer to vector ...
Well, I've stated my case. I have sinned. Now it's up to you to forgive me or not :)
Actually, there is nothing wrong with public inheritance of std::vector. If you need this, just do that.
I would suggest doing that only if it is really necessary. Only if you can't do what you want with free functions (e.g. should keep some state).
The problem is that MyVector is a new entity. It means a new C++ developer should know what the hell it is before using it. What's the difference between std::vector and MyVector? Which one is better to use here and there? What if I need to move std::vector to MyVector? May I just use swap() or not?
Do not produce new entities just to make something to look better. These entities (especially, such common) aren't going to live in vacuum. They will live in mixed environment with constantly increased entropy.
The whole STL was designed in such way that algorithms and containers are separate.
This led to a concept of different types of iterators: const iterators, random access iterators, etc.
Therefore I recommend you to accept this convention and design your algorithms in such way that they won't care about what is the container they're working on - and they would only require a specific type of iterator which they'd need to perform their operations.
Also, let me redirect you to some good remarks by Jeff Attwood.
The main reason for not inheriting from std::vector publicly is an absence of a virtual destructor that effectively prevents you from polymorphic use of descendants. In particular, you are not allowed to delete a std::vector<T>* that actually points at a derived object (even if the derived class adds no members), yet the compiler generally can't warn you about it.
Private inheritance is allowed under these conditions. I therefore recommend using private inheritance and forwarding required methods from the parent as shown below.
class AdVector: private std::vector<double>
{
typedef double T;
typedef std::vector<double> vector;
public:
using vector::push_back;
using vector::operator[];
using vector::begin;
using vector::end;
AdVector operator*(const AdVector & ) const;
AdVector operator+(const AdVector & ) const;
AdVector();
virtual ~AdVector();
};
You should first consider refactoring your algorithms to abstract the type of container they are operating on and leave them as free templated functions, as pointed out by majority of answerers. This is usually done by making an algorithm accept a pair of iterators instead of container as arguments.
If you're considering this, you've clearly already slain the language pedants in your office. With them out of the way, why not just do
struct MyVector
{
std::vector<Thingy> v; // public!
void func1( ... ) ; // and so on
}
That will sidestep all the possible blunders that might come out of accidentally upcasting your MyVector class, and you can still access all the vector ops just by adding a little .v .
What are you hoping to accomplish? Just providing some functionality?
The C++ idiomatic way to do this is to just write some free functions that implement the functionality. Chances are you don't really require a std::vector, specifically for the functionality you're implementing, which means you're actually losing out on reusability by trying to inherit from std::vector.
I would strongly advise you to look at the standard library and headers, and meditate on how they work.
I think very few rules should be followed blindly 100% of the time. It sounds like you've given it quite a lot of thought, and are convinced that this is the way to go. So -- unless someone comes up with good specific reasons not to do this -- I think you should go ahead with your plan.
There is no reason to inherit from std::vector unless one wants to make a class that works differently than std::vector, because it handles in its own way the hidden details of std::vector's definition, or unless one has ideological reasons to use the objects of such class in place of std::vector's ones. However, the creators of the standard on C++ did not provide std::vector with any interface (in the form of protected members) that such inherited class could take advantage of in order to improve the vector in a specific way. Indeed, they had no way to think of any specific aspect that might need extension or fine-tune additional implementation, so they did not need to think of providing any such interface for any purpose.
The reasons for the second option can be only ideological, because std::vectors are not polymorphic, and otherwise there is no difference whether you expose std::vector's public interface via public inheritance or via public membership. (Suppose you need to keep some state in your object so you cannot get away with free functions). On a less sound note and from the ideological point of view, it appears that std::vectors are a kind of "simple idea", so any complexity in the form of objects of different possible classes in their place ideologically makes no use.
In practical terms: If you do not have any data members in your derived class, you do not have any problems, not even in polymorphic usage. You only need a virtual destructor if the sizes of the base class and the derived class are different and/or you have virtual functions (which means a v-table).
BUT in theory: From [expr.delete] in the C++0x FCD: In the first alternative (delete object), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined.
But you can derive privately from std::vector without problems.
I have used the following pattern:
class PointVector : private std::vector<PointType>
{
typedef std::vector<PointType> Vector;
...
using Vector::at;
using Vector::clear;
using Vector::iterator;
using Vector::const_iterator;
using Vector::begin;
using Vector::end;
using Vector::cbegin;
using Vector::cend;
using Vector::crbegin;
using Vector::crend;
using Vector::empty;
using Vector::size;
using Vector::reserve;
using Vector::operator[];
using Vector::assign;
using Vector::insert;
using Vector::erase;
using Vector::front;
using Vector::back;
using Vector::push_back;
using Vector::pop_back;
using Vector::resize;
...
If you follow good C++ style, the absence of virtual function is not the problem, but slicing (see https://stackoverflow.com/a/14461532/877329)
Why is absence of virtual functions not the problem? Because a function should not try to delete any pointer it receives, since it does not have an ownership of it. Therefore, if following strict ownership policies, virtual destructors should not be needed. For example, this is always wrong (with or without virtual destructor):
void foo(SomeType* obj)
{
if(obj!=nullptr) //The function prototype only makes sense if parameter is optional
{
obj->doStuff();
}
delete obj;
}
class SpecialSomeType:public SomeType
{
// whatever
};
int main()
{
SpecialSomeType obj;
doStuff(&obj); //Will crash here. But caller does not know that
// ...
}
In contrast, this will always work (with or without virtual destructor):
void foo(SomeType* obj)
{
if(obj!=nullptr) //The function prototype only makes sense if parameter is optional
{
obj->doStuff();
}
}
class SpecialSomeType:public SomeType
{
// whatever
};
int main()
{
SpecialSomeType obj;
doStuff(&obj);
// The correct destructor *will* be called here.
}
If the object is created by a factory, the factory should also return a pointer to a working deleter, which should be used instead of delete, since the factory may use its own heap. The caller can get it form of a share_ptr or unique_ptr. In short, do not delete anything you didn't get directly from new.
Yes it's safe as long as you are careful not to do the things that are not safe... I don't think I've ever seen anyone use a vector with new so in practice you'll likely be fine. However, it's not the common idiom in c++....
Are you able to give more information on what the algorithms are?
Sometimes you end up going down one road with a design and then can't see the other paths you might have taken - the fact that you claim to need to vector with 10 new algorithms rings alarm bells for me - are there really 10 general purpose algorithms that a vector can implement, or are you trying to make an object that is both a general purpose vector AND which contains application specific functions?
I'm certainly not saying that you shouldn't do this, it's just that with the information you've given alarm bells are ringing which makes me think that maybe something is wrong with your abstractions and there is a better way to achieve what you want.
I also inherited from std::vector recently, and found it to be very useful and so far I haven't experienced any problems with it.
My class is a sparse matrix class, meaning that I need to store my matrix elements somewhere, namely in an std::vector. My reason for inheriting was that I was a bit too lazy to write interfaces to all the methods and also I am interfacing the class to Python via SWIG, where there is already good interface code for std::vector. I found it much easier to extend this interface code to my class rather than writing a new one from scratch.
The only problem I can see with the approach is not so much with the non-virtual destructor, but rather some other methods, which I would like to overload, such as push_back(), resize(), insert() etc. Private inheritance could indeed be a good option.
Thanks!
This question is guaranteed to produce breathless pearl-clutching, but in fact there is no defensible reason for avoiding, or "unnecessarily multiplying entities" to avoid, derivation from a Standard container. The simplest, shortest possible expression is clearest, and best.
You do need to exercise all the usual care around any derived type, but there is nothing special about the case of a base from the Standard. Overriding a base member function could be tricky, but that would be unwise to do with any non-virtual base, so there is not much special here. If you were to add a data member, you would need to worry about slicing if the member had to be kept consistent with contents of the base, but again that is the same for any base.
The place where I have found deriving from a standard container particularly useful is to add a single constructor that does precisely the initialization needed, with no chance of confusion or hijacking by other constructors. (I'm looking at you, initialization_list constructors!) Then, you can freely use the resulting object, sliced -- pass it by reference to something expecting the base, move from it to an instance of the base, what have you. There are no edge cases to worry about, unless it would bother you to bind a template argument to the derived class.
A place where this technique will be immediately useful in C++20 is reservation. Where we might have written
std::vector<T> names; names.reserve(1000);
we can say
template<typename C>
struct reserve_in : C {
reserve_in(std::size_t n) { this->reserve(n); }
};
and then have, even as class members,
. . .
reserve_in<std::vector<T>> taken_names{1000}; // 1
std::vector<T> given_names{reserve_in<std::vector<T>>{1000}}; // 2
. . .
(according to preference) and not need to write a constructor just to call reserve() on them.
(The reason that reserve_in, technically, needs to wait for C++20 is that prior Standards don't require the capacity of an empty vector to be preserved across moves. That is acknowledged as an oversight, and can reasonably be expected to be fixed as a defect in time for '20. We can also expect the fix to be, effectively, backdated to previous Standards, because all existing implementations actually do preserve capacity across moves; the Standards just haven't required it. The eager can safely jump the gun -- reserving is almost always just an optimization anyway.)
Some would argue that the case of reserve_in is better served by a free function template:
template<typename C>
auto reserve_in(std::size_t n) { C c; c.reserve(n); return c; }
Such an alternative is certainly viable -- and could even, at times, be infinitesimally faster, because of *RVO. But the choice of derivation or free function should be made on its own merits, and not from baseless (heh!) superstition about deriving from Standard components. In the example use above, only the second form would work with the free function; although outside of class context it could be written a little more concisely:
auto given_names{reserve_in<std::vector<T>>(1000)}; // 2
Here, let me introduce 2 more ways to do want you want. One is another way to wrap std::vector, another is the way to inherit without giving users a chance to break anything:
Let me add another way of wrapping std::vector without writing a lot of function wrappers.
#include <utility> // For std:: forward
struct Derived: protected std::vector<T> {
// Anything...
using underlying_t = std::vector<T>;
auto* get_underlying() noexcept
{
return static_cast<underlying_t*>(this);
}
auto* get_underlying() const noexcept
{
return static_cast<underlying_t*>(this);
}
template <class Ret, class ...Args>
auto apply_to_underlying_class(Ret (*underlying_t::member_f)(Args...), Args &&...args)
{
return (get_underlying()->*member_f)(std::forward<Args>(args)...);
}
};
Inheriting from std::span instead of std::vector and avoid the dtor problem.
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).