Suppose there is a class with several (e.g. 2) containers as private members. Would that be good to have different kinds of begin() (or at()) member functions to access iterator (or element) of the corresponding container?
Here is the small example:
class Example
{
private:
std::vector<double> A;
std::vector<double> B;
public:
double& A(std::size_t index) { return A.at(index); }
double& B(std::size_t index) { return B.at(index); }
};
I need to have such kind of access because there is one class that asks for the values in container A and there is also another class asking for the contents of B. In general class Example might have more than two containers.
Is that a good idea or there is better solution?
Thanks
EDIT
Here is some additional information: container A Holds always some parameters that will be passed to different functions, container B holds the values return from the function that has been passed container A as an argument. And the rest of possible containers will hold different constraints on the values that can be stored in A
Does anything outside of the class care about the contents of these vectors? If not, create a member function to take a function pointer and use it with the vectors. Then you don't need to expose the vectors. Fully exposing internal objects with get functions defeats the point of making them private.
If there might be more, it seems like you actually have some kind of "list" of containers. Almost like your naming scheme A, B, ... is just enumerating them, which is always a sign you should be using some sort of container. Then maybe you actually want a container of std::vectors? If it's a fixed amount, something like:
std::array<std::vector<double>, N> containers;
If it's not fixed, then:
std::vector<std::vector<double>> containers;
Then you could have a single function that asks for the index of the container and then an index within that container:
double& get(std::size_t container, std::size_t element) {
return containers[container][element];
}
It sounds like you need such accessors. You might consider putting const keyword on the returned value if elements doesn't have to be modified
const double& getA(std::size_t index) { return A.at(index); }
Related
Let's assume this class hierarchy below.
class BaseClass {
public:
int x;
}
class SubClass1 : public BaseClass {
public:
double y;
}
class SubClass2 : public BaseClass {
public:
float z;
}
...
I want to make a heterogeneous container of these classes. Since the subclasses are derived from the base class I can make something like this:
std::vector<BaseClass*> container1;
But since C++17 I can also use std::variant like this:
std::vector<std::variant<SubClass1, SubClass2, ...>> container2;
What are the advantages/disadvantages of using one or the other? I am interested in the performance too.
Take into consideration that I am going to sort the container by x, and I also need to be able to find out the exact type of the elements. I am going to
Fill the container,
Sort it by x,
Iterate through all the elements, find out the type, use it accordingly,
Clear the container, then the cycle starts over again.
std::variant<A,B,C> holds one of a closed set of types. You can check whether it holds a given type with std::holds_alternative, or use std::visit to pass a visitor object with an overloaded operator(). There is likely no dynamic memory allocation, however, it is hard to extend: the class with the std::variant and any visitor classes will need to know the list of possible types.
On the other hand, BaseClass* holds an unbounded set of derived class types. You ought to be holding std::unique_ptr<BaseClass> or std::shared_ptr<BaseClass> to avoid the potential for memory leaks. To determine whether an instance of a specific type is stored, you must use dynamic_cast or a virtual function. This option requires dynamic memory allocation, but if all processing is via virtual functions, then the code that holds the container does not need to know the full list of types that could be stored.
A problem with std::variant is that you need to specify a list of allowed types; if you add a future derived class you would have to add it to the type list. If you need a more dynamic implementation, you can look at std::any; I believe it can serve the purpose.
I also need to be able to find out the exact type of the elements.
For type recognition you can create a instanceof-like template as seen in C++ equivalent of instanceof. It is also said that the need to use such a mechanism sometimes reveals poor code design.
The performance issue is not something that can be detected ahead of time, because it depends on the usage: it's a matter of testing different implementations and see witch one is faster.
Take into consideration that, I am going to sort the container by x
In this case you declare the variable public so sorting is no problem at all; you may want to consider declaring the variable protected or implementing a sorting mechanism in the base class.
What are the advantages/disadvantages of using one or the other?
The same as advantages/disadvantages of using pointers for runtime type resolution and templates for compile time type resolution. There are many things that you might compare. For example:
with pointers you might have memory violations if you misuse them
runtime resolution has additional overhead (but also depends how would you use this classes exactly, if it is virtual function call, or just common member field access)
but
pointers have fixed size, and are probably smaller than the object of your class will be, so it might be better if you plan to copy your container often
I am interested in the performance too.
Then just measure the performance of your application and then decide. It is not a good practice to speculate which approach might be faster, because it strongly depends on the use case.
Take into consideration that, I am going to sort the container by x
and I also need to be able to find out the exact type of the elements.
In both cases you can find out the type. dynamic_cast in case of pointers, holds_alternative in case of std::variant. With std::variant all possible types must be explicitly specified. Accessing member field x will be almost the same in both cases (with the pointer it is pointer dereference + member access, with variant it is get + member access).
Sending data over a TCP connection was mentioned in the comments. In this case, it would probably make the most sense to use virtual dispatch.
class BaseClass {
public:
int x;
virtual void sendTo(Socket socket) const {
socket.send(x);
}
};
class SubClass1 final : public BaseClass {
public:
double y;
void sendTo(Socket socket) const override {
BaseClass::sendTo(socket);
socket.send(y);
}
};
class SubClass2 final : public BaseClass {
public:
float z;
void sendTo(Socket socket) const override {
BaseClass::sendTo(socket);
socket.send(z);
}
};
Then you can store pointers to the base class in a container, and manipulate the objects through the base class.
std::vector<std::unique_ptr<BaseClass>> container;
// fill the container
auto a = std::make_unique<SubClass1>();
a->x = 5;
a->y = 17.0;
container.push_back(a);
auto b = std::make_unique<SubClass2>();
b->x = 1;
b->z = 14.5;
container.push_back(b);
// sort by x
std::sort(container.begin(), container.end(), [](auto &lhs, auto &rhs) {
return lhs->x < rhs->x;
});
// send the data over the connection
for (auto &ptr : container) {
ptr->sendTo(socket);
}
It's not the same. std::variant is like a union with type safety. No more than one member can be visible at the same time.
// C++ 17
std::variant<int,float,char> x;
x = 5; // now contains int
int i = std::get<int>(v); // i = 5;
std::get<float>(v); // Throws
The other option is based on inheritance. All members are visible depending on which pointer you have.
Your selection will depend on if you want all the variables to be visible and what error reporting you want.
Related: don't use a vector of pointers. Use a vector of shared_ptr.
Unrelated: I'm somewhat not of a supporter of the new union variant. The point of the older C-style union was to be able to access all the members it had at the same memory place.
I'm building an C++ API just for learning purposes and I'll need a class
with two containers. Suppose they're initially of type vector<>.
class MyClass
{
private:
std::vector<int> containerA;
std::vector<double> containerB;
public:
std::vector<int> *getContainerA();
std::vector<double> *getContainerB();
};
But if someday I'll have to change the type of these containers (to list, for instance), I would not want that the users of this API needed to change anything in their code.
So, considering that containerA and containerB types were changed, when using the getters above, which return vector<>, API users would need to change their code to match the new type of API's containers.
I think that return iterators instead of vector<> can help me with that.
class MyClass
{
private:
std::vector<int> containerA;
std::vector<double> containerB;
public:
std::vector<int>::iterator beginContainerA() { return containerA.begin(); }
std::vector<int>::iterator endContainerA() { return containerA.end(); }
std::vector<double>::iterator beginContainerB() { return containerB.begin(); }
std::vector<double>::iterator endContainerB() { return containerB.end(); }
};
Is this the way how things are done? Is there a better way? Thank you.
I recommend combining πάντα ῥεῖ's idea and yours: Both define a type alias, and return iterators:
typedef std::vector<int> ContainerAType;
ContainerAType::iterator beginContainerA();
Also, you'll need a const version as well, so that you can use the iterators on const instances:
ContainerAType::const_iterator beginContainerA() const;
Consider whether non-const access is even needed.
Consider returning a range of iterators instead:
boost::iterator_range<ContainerAType::iterator> containerA();
However, to truly protect the client from any changes, you will need to use type erasing iterator. With type erasure, the client does not even need to recompile, if you change from vector to list (but you also have to use pimpl pattern, to achieve that). You could even stop using a container entirely, and return custom iterators, that generate the data.
Boost has you covered: http://www.boost.org/doc/libs/1_54_0/libs/range/doc/html/range/reference/ranges/any_range.html Type erasing iterators do have some overhead, due to using a virtual function call internally.
Rather use getters like
const std::vector<int>& getContainerA() const { return containerA; }
and let your clients use
std::vector<int>::const_iterator
from the reference.
But if someday I'll have to change the type of these containers (to list, for instance), I would not want that the users of this API needed to change anything in their code.
Also you can use a class specific typedef to expose the underlying container type:
typedef std::vector<int> ContainerAType;
const ContainerAType& getContainerA() const { return containerA; }
Note that handing out iterators is bad, in the sense that these may become invalid upon changes to the underlying containers.
If a client should be notified about changes, you'll need a separate mechanism like e.g. an Observer .
I'm porting some Fortran90 code to C++ (because I'm stupid, to save the "Why?!").
Fortran allows specification of ranges on arrays, in particular, starting at negative values, eg
double precision :: NameOfArray(FirstSize, -3:3)
I can write this in C++ as something like
std::array<std::array<double, 7>, FirstSize> NameOfArray;
but now I have to index like NameOfArray[0:FirstSize-1][0:6]. If I want to index using the Fortran style index, I can write perhaps
template <typename T, size_t N, int start>
class customArray
{
public:
T& operator[](const int idx) { return data_[idx+start]; }
private:
std::array<T,N> data_;
}
and then
customArray<double, 7, -3> NameOfArray;
NameOfArray[-3] = 5.2;
NameOfArray[3] = 2.5;
NameOfArray[4] = 3.14; // This is out of bounds,
// despite being a std::array of 7 elements
So - the general idea is "Don't inherit from std::'container class here'".
My understanding is that this is because, for example, std::vector does not have a virtual destructor, and so should not (can not?) be used polymorphically.
Is there some other way I can use a std::array, std::vector, etc, and get their functions 'for free', whilst overriding specific functions?
template<typename T, size_t N>
T& std::array<T,N>::operator[](const int idx) { ... };
might allow me to override the operator, but it won't give me access to knowledge about a custom start point - making it completely pointless. Additionally, if I were to optimistically think all my customArray objects would have the same offset, I could hardcode that value - but then my std::array is broken (I think).
How can I get around this? (Ignoring the simple answer - don't - just write myArray[idx-3] as needed)
There's no problem with inheriting standard containers. This is only generally discouraged because this imposes several limitations and such an inheritance is not the way how inheritance was originally predicted in C++ to be used. If you are careful and aware of these limitations, you can safely use inheritance here.
You just need to remember that this is not subclassing and what this really means. In particular, you shouldn't use pointers or references to the object of this class. The problem might be if you pass a value of MyVector<x>* where vector<x>* was expected. You should also never create such objects as dynamic (using new), and therefore also delete these objects through the pointer to the base class - simply because destructor call will not forward to your class's destructor, as it's not virtual.
There's no possibility to prevent casting of the "derived pointer" to the "base pointer", but you can prevent taking a pointer from an object by overloading the & operator. You can also prevent creating objects of this class dynamically by declaring an in-class operator new in private section (or = delete should work as well).
Don't also think about private inheritance. This is merely like containing this thing as a field in private section, except the accessor name.
A range converter class could be the solution although you would need to make it yourself, but it would allow you to get the range size to initialize the vector and to do the conversion.
Untested code:
struct RangeConv // [start,end[
{
int start, end;
RangeConv(int s, int e) : start(s), end(e) { }
int size() const { return end - start; }
int operator()(int i) { return i - start; } // possibly check whether in range
}
RangeConv r(-3, 3);
std::vector<int> v(r.size());
v[r(-3)] = 5;
so should not (can not?) be used polymorphically.
Don't give up too soon. There are basically two issues to consider with inheritance in C++.
Lifetime
Such objects, derived classes with non-virtual destructors in the base, can be used safely in a polymorphic fashion, if you basically follow one simple rule: don't use delete anywhere. This naturally means that you cannot use new. You generally should be avoiding new and raw pointers in modern C++ anyway. shared_ptr will do the right thing, i.e. safely call the correct destructor, as long as you use make_shared:
std:: shared_ptr<Base> bp = std:: make_shared<Derived>( /* constructor args */ );
The type parameter to make_shared, in this case Derived, not only controls which type is created. It also controls which destructor is called. (Because the underlying shared-pointer object will store an appropriate deleter.)
It's tempting to use unique_ptr, but unfortunately (by default) it will lead to the wrong deleter being used (i.e. it will naively use delete directly on the base pointer). It's unfortunate that, alongside the default unique_ptr, there isn't a much-safer-but-less-efficient unique_ptr_with_nice_deleter built into the standard.
Polymorphism
Even if std::array did have a virtual destructor, this current design would still be very weird. Because operator[] is not virtual, then casting from customArray* to std:: array* would lead to the wrong operator[]. This isn't really a C++-specific issue, it's basically the issue that you shouldn't pretend that customArray isa std:: array.
Instead, just decide that customArray is a separate type. This means you couldn't pass an customArray* to a function expecting std::array* - but are you sure you even want that anyway?
Is there some other way I can use a std::array, std::vector, etc, and get their functions 'for free', whilst overloading specific functions?
This is a good question. You do not want your new type to satisfy isa std::array. You just want it to behave very similar to it. As if you magically copied-and-pasted all the code from std::array to create a new type. And then you want to adjust some things.
Use private inheritance, and using clauses to bring in the code you want:
template <typename T, size_t N, int start>
struct customArray : private std::array<T,N>
{
// first, some functions to 'copy-and-paste' as-is
using std::array<T,N> :: front;
using std::array<T,N> :: begin;
// finally, the functions you wish to modify
T& operator[](const int idx) { return data_[idx+start]; }
}
The private inheritance will block conversions from customArray * to std::array *, and that's what we want.
PS: I have very little experience with private inheritance like this. So many it's not the best solution - any feedback appreciated.
General thought
The recommendation not to inherit from standard vector, is because this kind of construct is often misunderstood, and some people are tempted to make all kind of objects inherit from a vector, just for minor convenience.
But this rule should'nt become a dogma. Especially if your goal is to make a vector class, and if you know what you're doing.
Danger 1: inconsistency
If you have a very important codebase working with vectors in the range 1..size instead of 0..size-1, you could opt for keeping it according to this logic, in order not to add thousands of -1 to indexes, +1 to index displayed, and +1 for sizes.
A valid approach could be to use something like:
template <class T>
class vectorone : public vector<T> {
public:
T& operator[] (typename vector<T>::size_type n) { return vector<T>::operator[] (n-1); }
const T& operator[] (typename vector<T>::size_type n) const { return vector<T>::operator[] (n-1); }
};
But you have to remain consitent accross all the vector interface :
First, there's also a const T& operator[](). If youd don't overload it, you'll end up having wrong behaviour if you have vectors in constant objects.
Then, and it's missing above, theres's also an at() which shall be consitent with []
Then you have to take extreme care with the constructors, as there are many of them, to be sure that your arguments will not be misinterpreted.
So you have free functionality, but there's more work ahead than initially thougt. The option of creating your own object with a more limited interface, and a private vector could in the end be a safer approach.
Danger 2:more inconsistency
The vector indexes are vector<T>::size_type. Unfortunately this type is unsigned. The impact of inherit from vector, but redefine operator[] with signed integer indexes has to be carefully analysed. This can lead to subtle bugs according to the way the indexes are defined.
Conclusions:
There's perhap's more work that you think to offer a consistent std::vector interface. So in the end, having your own class using a private vector could be the safer approach.
You should also consider that your code will be maintained one day by people without fortran background, and they might have wrong assumptions about the [] in your code. Is going native c++ really out of question ?
It doesn't seem that bad to just stick with composition, and write wrappers for the member functions you need. There aren't that many. I'd even be tempted to make the array data member public so you can access it directly when needed, although some people would consider that a bigger no-no than inheriting from a base class without a virtual destructor.
template <typename T, size_t N, int start>
class customArray
{
public:
std::array<T,N> data;
T& operator[](int idx) { return data[idx+start]; }
auto begin() { return data.begin(); }
auto begin() const { return data.begin(); }
auto end() { return data.end(); }
auto end() const { return data.end(); }
auto size() const { return data.size(); }
};
int main() {
customArray<int, 7, -3> a;
a.data.fill(5); // can go through the `data` member...
for (int& i : a) // ...or the wrapper functions (begin/end).
cout << i << endl;
}
I have many class that has inside list<cats> , and i want to allow users that use my class to iterate over the cats i have, so i give them access to a const iterator by writing the following function :
list<cats>::const_iterator GetIterator()
{
//return the iterator
}
Now i want to change my implementation of the class and use vector instead of list, so i need to return a const iterator of vector.
The problem is that every one that uses my class now need to change their code from list<cats>::const_iterator to vector<cat>::const_iterator.
If all the iterators where to inherit from "forward iterator" it would be very useful.
My major question is how i solve this problem, i don't want to inherit from a collection.
Another very related question is why the designers of STL chose not to inherit iterators one from another ? (for example random access iterators could have inherit from forward iterators, he have all it's functionality)
I did pretty extensive search before i asked my question but couldn't find the solution.
The closest thing i found to my question is this, but it is not exactly my question.
Give access to encapsulated container
Expose an iterator type from your class, e.g:
class a
{
vector<int> g;
public:
typdef vector<int>::const_iterator const_iterator;
const_iterator begin() const
{ return g.begin(); }
: // etc
};
If the users can recompile the code you can use
typedef list<cats> CatList;
in your include file. Then, if you want to change the container, change it to
typedef vector<cats> CatList;
and the users would use e.g.
CatList::iterator it;
However this is not a good practice; the iterators of different containers may look equal but behave differently e.g. deleting an item from a vector invalidates all iterators but doing the same on list affects only iterator of deleted item. Not mentioning the case if some day you want to use std::map<some_key,cats>.
I agree with Nim's answer and wanted to offer the style I follow which I think makes maintenance easier since now changing the underlying container type requires no work at all for users of your class and very little work for you when maintaining your class.
class A
{
// change only this to change the underlying container:
// Don't Repeat Yourself!
using container_t = std::vector<int>;
public:
// constructor from a copy of a container
A(container_t source)
: _myContainer { std::move(source) }
{}
// this derived type is part of the public interface
using const_iterator_t = container_t::const_iterator;
// following your function naming style...
const_iterator_t GetIterator() const { return /* some iterator of _myContainer */; }
const_iterator_t GetEnd() const { return std::end(_myContainer); }
private:
container_t _myContainer;
};
Actually, I have a design question here. Its very simple but the point is:
I have one C++ class that has a STL vector declared as a private member. But the clients of that class need to iterate over this vector.
In C# we have a very handy statement, the Yield, that in cases like that, you write a function returning an IEnumerable and it "yields" you a nice way to iterate over a private container inside that class.
I'm just trying to find an elegant solution for C++, instead of using methods like GetValue(int idx).
Any suggestions?
Example:
class Fat
{
public:
Fat();
// some code here ...
private:
void LoadSectors(SECT startPoint);
std::vector<SECT>sectors;
};
class Storage
{
public:
Storage(string CompoundFile);
//For example, this method will receive a ref to my fat system and iterate over
//the fat array in order to read every sector.
LoadStrem(Fat& fat);
};
This is far simple example.
There's no syntactic sugar in C++ analogous to yield in C#. If you want to create a class, instances of which should be iterable in the same way stock STL collections are, then you have to implement an iterator for your class, expose it as ::iterator on your type, and provide begin() and end() member functions.
You can either create an accessor function which returns a reference (or preferably const reference) to the vector, or you can create begin() and end() accessor functions which return the appropriate vector iterators.
It always hurts when you need to publish the innards of your class...
You may be able to solve it by providing algorithms as the stl does: provide a foreach function on the object's interface.
class S {
std::vector<int> v;
public:
//... and some methods to populate the vector
template< typename F > F& foreach( F& f ) {
return std::for_each( v.begin(), v.end(), f );
}
};
This way, the class remains 'closed', but you have the flexibility you need. You can also add a copy function, and maybe a transform; these are the ones I most frequently need.
Let your class expose iterators.
class Fat
{
public:
typedef std::vector<SECT>::iterator iterator;
iterator begin() { return sectors.begin(); }
iterator end() { return sectors.end(); }
Fat();
// some code here ...
private:
void LoadSectors(SECT startPoint);
std::vector<SECT>sectors;
Then the surrounding code can traverse the elements of the vector freely, through just a pair of iterators.