I have a container called "ntuple" that is essentially a C array and length. It's main purpose is to be the argument of multi-dimensional math functions. As of now, it's really fast and utilizes several constructors of the form
ntuple(double x, double y, double z)
{
size = 3;
vec = new double[size];
vec[0] = x;
vec[1] = y;
vec[2] = z;
}
And every time I work with a higher dimensional, yet known function, I just add a new constructor. I have on for an array as well:
ntuple(double* invec, long unsigned insizesize)
In order to make my code more compatible with regular c++ code, should I implement an ntuple iterator class? Nothing I've done has needed one and it seems like it will just slow everything down. But the more I read, the more vital it seems to use iterators for the sake of compatibility with standard C++ code.
I worry that when someone tries to work with my code, it won't mesh well with the standard techniques that they expect to use. But the purpose of my ntuple class is just to take arguments into functions.
Should I implement the iterators just as a precaution (if someone else will try to use the STL on it) at the cost of slowing my code?
Thanks.
Implementing iterators for a wrapper around a C array is trivial -- just return pointers to the first, and one-past-the-last, element for begin and end respectively, and adding non-virtual methods to a POD class won't slow down much of anything. Accessing the array via these methods won't be any slower than using array index lookups, and can be faster in some contexts. And if you don't use them, your code won't run slower.
As an advantage, in C++11 if you have a begin and end method, std::begin and std::end will find it, and for( auto x: container ) { /* code */ } will work on your type.
As this seems to be an X/Y problem, I suspect one of your problems is that you shouldn't be using your ntuple class at all. std::vector<double> is already a thin wrapper around a C-style array that is well written. To pass it without the cost of copying it, std::vector<double> const&.
As a pedantic aside, the STL refers to the library from which the template component of std was derived. It differs slightly from the std library in a few ways.
Yes, use vector but (if you really have lots of data in memory) be very careful to manage vector's memory. Then you will really have this 4 byte overhead (wasted for capacity).
allways create vector with explicit size, or create empty and use resize()
fill vector using indices (as you do vec[0] = ...)
never use push_back - it can request (twice) more memory than needed
You can also enforce this rules with inheriting vector (though sometimes this practice is not recommended) like this
class ntuple: public std::vector<double> {
private:
typedef std::vector<double> super;
void push_back(double); // do not implement
// also forbid pop_back()
public:
ntuble(double a, double b) {
resize(2);
(*this)[0] = a;
(*this)[1] = b;
}
ntuple(double* invec, long unsigned size)
: super(invec, invec + size)
{
}
// all your other convenient constructors here
};
iterators will still be accessible with begin() and end() methods
Related
I want to have a certain kind of std::vector that cannot have more than const int MAX_LENGTH elements. I understand that I cannot override std::vector non-virtual functions, which I'd need to do to put a size check in all the relevant member functions (e.g., assign, push_back...there are so many). The most obvious way to do this is to wrap std::vector in a class that ensures no operation adds beyond the maximum length. But this seems clunky. Is there a more elegant solution than a wrapper class to limit std::vector size?
Are you sure that the vector itself can't grow, or that merely the consumers of such a vector need to limit the size of the arguments? If it's the latter, then simply assert(arg.size() <= MAX_LENGTH) where needed, document it, and be done. Otherwise, read on.
A std::vector can have unlimited size. If you limit that size, it's not a std::vector anymore. So, you cannot publicly derive from std::vector and limit the size without breaking the Liskov Substitution Principle. The derived class is still a vector, but doesn't act as one, and can't be used as one, and such an interface will thoroughly confuse your users, and the compiler will not catch serious usage bugs that will ensue. It's a bad idea.
The best you can do is to privately derive from vector, or have-a vector as a member, and expose all of the vector's interfaces while enforcing the size. Such a vector must not be convertible to std::vector, although obviously you can allow it to be copied or moved to a std::vector. It'll still perform just as well as a vector would, will still allow access via iterators, etc.
We're talking of a very small class, and its implementation simply has to follow the standard (or at least the cpp reference), you're leaving all the real work to the private std::vector. So that's not clunky, that's the only sane way to do it.
Since C++11, custom allocators are permitted to have state (previous to C++11, custom allocators had to be stateless). Each C++ container that takes a custom allocator stores an instance of it.
Your allocator can then detect whether or not it has already fulfilled a request for the maximum allotment, and throw otherwise.
#include <vector>
#include <string>
using namespace std;
template <typename T, typename A>
void add_or_throw(std::vector<T,A> &vec, int max, T value)
{
if (vec.size() < max)
{
vec.push_back(value);
}else{
throw length_error("vecor too beaucoup");
}
}
int main() {
std::vector<std::string> v;
add_or_throw(v, 2, string("hi"));
add_or_throw(v, 2, string("there"));
add_or_throw(v, 2, string("man!"));
return 0;
}
I have meet such a question.
I need to design a interface class, which looks like to be
struct IIDs
{
....
const std::set<int>& getAllIDs() = 0; //!< I want the collection of int to be sorted.
}
void foo()
{
const std::set<int>& ids = pIIDs->getAllIDs();
for(std::set<int>::const_iterator it = ids.begin();....;..) {
// do something
}
}
I think that return a std's container is a bit of inappropriate, for that it will force the implement to use a std::set to store the value of IDs, But If I write it as follow :
struct IIDs
{
....
int count() const = 0;
int at(int index) = 0; //!< the itmes should be sorted
}
void foo()
{
for (int i = 0; i < pIIDs->count(); ++i) {
int val = pIIDs->at(u);
...
}
}
I found that none of the std's containers could provide those requests:
the complexity of index lookup needed to less or equal than O(log n).
the complexity of insertion need to less or equal than O(log n).
the items must be sorted.
So I just have to use the example.1, Is those can be acceptable?
STL containers and template code in general should never be used across a DLL boundary.
The thing you have to keep in mind when returning complex types like STL containers is that if your call ever crosses the boundary between two different DLLs (or a DLL and an application) running different memory managers your application will most likely crash spectacularly.
The templates that make up the STL code will be executed within the implementation DLL, creating all the memory used by the container there. Later when it leaves scope in your calling code, your own memory manager will attempt to deallocate memory it doesn't own, resulting in a crash.
If you know your code won't cross DLL boundaries, and will only ever be called in the context of a single memory manager, then you're fine as far as memory management is concerned.
However, even in cases where you're only returning references, such as your example above, where the lifetime of the container would be entirely managed by the interface implementation code, unless you know that the exact same version of the STL and the exact same compiler and linker settings were used for compiling the implementation as the caller, you're asking for trouble.
The problem i see is you are returning the collection by const references, that mean that you have a member of that collection type and are returning a reference to it, if you are returning a local variable to the function (invalid memory access problems).
If it's a member variable is better provide access to begin and end iterator. If is local variable you could returned by value (C++11 should optimize and no copy anything). If it's DLL boundary try for all mean not use any C++ types, only C types.
In terms of design, and for good generic code, prefer the STL way: return iterators, leaving the container type an implementation detail of IIDs, and hide your types with typdefs
struct IIDs
{
typedef std::set<int> Container;
typedef Container::iterator IDIterator;
// We only expose iterators to the data
IDIterator begin(); //!< I want the collection of int to be sorted.
IDIterator end();
// ...
};
There are various approaches:
if you want to minimise the coupling of client code on the IIDs implementation and ensure iteration is completed while the IIDs object still exists, then use a visitor pattern: the calling code just has to supply some function to be called for each of the member elements in turn and is not responsible for the iteration itself
Visitor example:
struct IIDs
{
template <typename T>
void visit(T& t)
{
for (int i : ids_) t(i);
}
...
private:
std::set<int> ids_;
};
if you want to give the caller more freedom to mix other code in with the container traversal, and have multiple concurrent independent traversals, then provide iterators, but be aware that the client code could keep an iterator hanging around longer than the IIDs object itself - you may or may not want to handle that scenario gracefully
If you don't need dynamic growth and don't know the size of the buffer at compile time, when should unique_ptr<int[]> be used instead of vector<int> if at all?
Is there a significant performance loss in using vector instead of unique_ptr?
There is no performance loss in using std::vector vs. std::unique_ptr<int[]>. The alternatives are not exactly equivalent though, since the vector could be grown and the pointer cannot (this can be and advantage or a disadvantage, did the vector grow by mistake?)
There are other differences, like the fact that the values will be initialized in the std::vector, but they won't be if you new the array (unless you use value-initialization...).
At the end of the day, I personally would opt for std::vector<>, but I still code in C++03 without std::unique_ptr.
If you're in a position where vector<int> is even a possibility, you probably want to go with that except in extreme and rare circumstances. And even then, a custom type instead of unique_ptr<int[]> may well be the best answer.
So what the heck is unique_ptr<int[]> good for? :-)
unique_ptr<T[]> really shines in two circumstances:
1. You need to handle a malloc/free resource from some legacy function and you would like to do it in a modern exception safe style:
void
foo()
{
std::unique_ptr<char[], void(*)(void*)> p(strdup("some text"), std::free);
for (unsigned i = 0; p[i]; ++i)
std::cout << p[i];
std::cout << '\n';
}
2. You've need to temporarily secure a new[] resource before transferring it onto another owner:
class X
{
int* data_;
std::string name_;
static void validate(const std::string& nm);
public:
~X() {delete [] data_;}
X(int* data, const std::string& name_of_data)
: data_(nullptr),
name_()
{
std::unique_ptr<int[]> hold(data); // noexcept
name_ = name_of_data; // might throw
validate(name_); // might throw
data_ = hold.release(); // noexcept
}
};
In the above scenario, X owns the pointer passed to it, whether or not the constructor succeeds. This particular example assumes a noexcept default constructor for std::string which is not mandated. However:
This point is generalizable to circumstances not involving std::string.
A std::string default constructor that throws is lame.
std::vector stores the length of both the size of the variable and the size of the allocated data along with the pointer to the data it's self. std::unique_ptr just stores the pointer so there may be a small gain in using std::unique_ptr.
No one has yet mentioned the vector provides iterators and function such and size() where as unique ptr does not. So if iterators are needed use std::vector
C++14 introduces std::dynarray for that purpose.
Now, between these two constructions :
auto buffer = std::make_unique<int[]>( someCount );
auto buffer = std::vector<int>( someCount, someValue );
The first gives you an uninitialized array of int but the second initializes it with a value ( 0 if not provide ). So if you do not need the memory to be initialized because you will overwrite it somehow later with something more complex than std::fill, choose 1, if not, choose 2.
Objective Part:
No, there probably shouldn't be a significant performance difference between the two (though I suppose it depends on the implementation and you should measure if it's critical).
Subjective Part:
std::vector is going to give you a well known interface with .size() and .at() and iterators, which will play nicely with all sorts of other code. Using std::unique_ptr gives you a more primitive interface and makes you keep track of details (like the size) separately. Therefore, barring other constraints, I would prefer std::vector.
I have a (virtual) function which returns a std::vector with a single value. Let's assume the class looks like:
#include <vector>
class Z; // irrelevant
class C
{
Z& something;
public:
typedef std::vector<Z*> list_type;
virtual list_type f();
};
Is it better to use the repetitive constructor:
C::list_type C::f()
{
return list_type(1, &something);
}
or just push_back() the single element:
C::list_type C::f()
{
list_type ret;
ret.push_back(&something);
return ret;
}
If you consider "better" to be "short code", then probably the repetitive constructor is better because is shorter and therefore more concise.
In terms of functionality, both are equal.
In terms of performance, the repetitive constructor can be better because it can call reserve() as it knows beforehand the total number of elements that it's going to allocate. However, you are using it just to create an element, so I guess it does not matter.
They are basically equivalent in terms of functionality, but return list_type(1, &something); might be more efficient since you directly pre-allocate the vector to its desired capacity, plus you avoid a call to push_back.
If your compiler is new enough to handle C++11 initializer lists you could use that to say:
C::list_type C::f()
{
return list_type{&something};
}
In general, using repetitive form is better since vector then would allocate precisely N elements, initializing them with given value (as compared to reallocating underlying array for log2(N) times, which will happen in case of repetitive push_back()'s).
But in case of just one pointer, the difference is negligible; and using -O3 or whatever will probably turn these constructions into the same assembly code.
Coming from a PHP background, I'm trying to learn C++, since I find it an interesting language. As a practice I want to create a simple Vector class using templates, which is not to hard. However, I run into one problem.
I have created the following template class:
template <typename T>
class Vector
{
public:
Vector(int length);
~Vector(void);
int getLength();
T& operator[] (const int index);
private:
T *_items;
int _count;
};
template <typename T>
Vector<T>::Vector(int length)
{
_items = new T[length];
_count = length;
}
template <typename T>
T& Vector<T>::operator[]( const int index )
{
if (index >= getLength() || index < 0)
throw exception("Array out of bounds.");
return _items[index];
}
All functions are implemented, but they're not relevant to my question, so I haven't copied them here.
This class works as expected, with one exception:
If I want to create a vector of array's, it doesn't work.
e.g.:
Vector<int[2]> someVector(5);
What I obviously want is that the _items property of the vector class will be an int[5][2]. However, since the compiler replaces the 'T' with 'int[2]', the _items property will be int[2][5] (or at least, that's what I understood from debugging, please correct me if I'm wrong). As a result, the [] operator doesn't work correctly anymore, and therefore this whole class is useless for arrays.
Is there a way to solve this problem, so that this class also works for arrays? And if that's not possible, is there a way to prevent this class being initialized with arrays?
Edit: Thanks for all your responses so far. However, I might have been not entirely clear with my question. First of all, I created this class to get used to c++, I know there is a std::vector class, and I also now that it's better to use a vector of vectors. That's not really the problem. I just want to understand templates better, and c++ in general, so I want to know how to deal with this type of problems. I want to be able to create classes which don't make the program crash. If I, or someone else, would use this class right now and tried to use primitive arrays instead of vectors for this class, at some point the program will crash since the array is wrong (Vector(y) becomes int[x][y] instead of int[y][x] internally). So I want a solution which either creates the correct array, or prevents the vector being initialized with arrays at all.
Quite simply, don't ever use the in-built primitive arrays. For anything. They suck, tremendously. Always use a class wrapper such as boost::array, if you don't have TR1 or C++0x both of which also provide an array class. A Vector<boost::array<int, 2>> will trivially compile.
Why not use primitive arrays?
They have hideous implicit conversions to pointers, forget their size at the drop of a hat, aren't first-class citizens (can't assign to them, for example), don't check their bounds, for example. boost::array<int, 2> is exactly a primitive array without crappy conversions, is fully generic- for example, your Vector template works fine with a boost::array<int, 2> off the bat, and it can do bounds checking in the at() function.
I'm not suggesting using a dynamic array instead. boost::array is not a dynamically sized array. It is a constant size, value type array, that will not convert to a pointer, it has functions for use in the Standard library like begin, end, size, and it can be treated like any other type- unlike arrays, which have a dozen special rules- as you've found out.
I see a few things wrong with this.
If you are making a generic vector class, why deal with a vector of arrays rather than a vector of vectors?
Rather than defining a vector of type int[2], try making a vector of vectors of size 2 with something like this:
Vector<Vector<int>> vector(5);
for (int i = 0; i < 5; i++)
{
vector[i] = Vector<int>(2);
}
Rather than using a constant sized array, try using a pointer.
Rather than using a pointer to arrays of size 2, use a pointer to a pointer, and allocate two spaces for that pointer. Pointers are a lot easier to deal with in C++ because you can simply pass the address of the pointer rather than having to copy the entire array. It's generally very bad form to pass arrays.
Add a default parameter to your constructor
Rather than declaring the constructor with Vector(int length);, try using Vector(int length = 0); so that if the user doesn't specify a length it will default to a size of zero.
Finally, are you aware that there is in fact an std::vector, or are you aware of this and simply trying to replicate it? Templates are known to be one of the hardest subjects of C++, good luck!
The condition must say index >= getLength(), because getLength() is not an allowed index value too (the first element's index is 0, the last's is getLength()-1)