My goal is to take 3 standard integer arrays and use vector methods to manipulate them without having to copy all the array elements into a separate vector array.
The reason I want to do this without copying array elements is because these will be very large arrays and efficiency is a priority.
Here are two examples of what I'd like it to look like:
Simplest example:
int arr[10000];
int *ptr;
std::vector<int> & v = ptr;
v.push_back(10);
Function example:
// Function that inputs 3 integer arrays and creates pointers to them.
void use_vector(int *dst, int *src1, int *src2) {
//creates vector references (without copying the original array elements)
std::vector<int> & v_dst = dst;
std::vector<int> & v_src1 = src1;
std::vector<int> & v_src2 = src2;
// do something using vector methods:
v_dst.push_back( v_scr1.size() + v_scr2.size() );
}
In both cases, I get this error message:
error: invalid initialization of reference of type ‘std::vector<int>&’ from expression of type ‘int*’
std::vector<int> &v = ptr;
Ideally the vectors are references (std::vector &), but they could also be pointers (std::vector *) if references aren't possible.
You can't do it because std::vector is designed with ownership semantics on the data it holds.
This means that it is not designed to wrap an array of values and store it. It must own the data, so a copy is necessary (or a move from another std::vector).
You can't do anything like:
std::vector<int> & v = ptr;
because the left-hand side is a reference to a std::vector<int> and the right-hand side is a pointer to int.
Likewise for your second example.
Also you basically can't use a std::vector on an existing array in place. The usual way is to copy, which you say you don't want to do. Your left with defining you own class do give you the vector-like interface you want on an in place array.
Related
So, I'm creating a class that represents an arbitrarily-sized matrix, and I want to write a function that "exports" the internal Vector to a 2-dimensional array.
I've found some code that seems to do what I want. Here is what the code looks in my class:
// Export matrix to array
double** Matrix::a_data() const
{
vector<double*> ptrs;
for (auto& vec : mat)
{
ptrs.push_back(vec.data());
}
return ptrs.data();
}
where mat is the vector < vector < double > > used to store the matrix's entries.
The post in question stated that vec needed to be an auto& instead of an auto because it is "very important to prevent vec from being a temporary copy."
However, in Visual Studio I'm always getting an error "no instance of overloaded function push_back matches the argument list... argument types are (const double*)"
So, my question is, how can I get this to work without changing auto& to auto? Also, how would one extend this to 3 dimensions?
You are running into a const problem.
Assuming mat is of type std::vector<std::vector<double>>, vec will be of type std::vector<double> const& in the function. The data() member function for const objects returns const*, not a regular pointer.
Hence, you need to use:
vector<double const*> ptrs;
But then, using
return ptrs.data();
is going to cause bigger problems. ptrs is function local variable. It is going to be destructed when the function returns. Hence, the returned pointer will be a dangling pointer.
Options to overcome that problem.
Change the return type to std::vector<double const*>.
Create a dynamic array of double const** and return it.
I strongly recommend the first option.
I would like to create a C++ Class which takes a "vector" int t[9] as argument. I don't understand why my code isn't working :
Here is the content of the header :
class Matrice3x3{
public:
int n;
int t[9];
Matrice3x3 inverse();
float det();
void print();
Matrice3x3(int u = 3);
Matrice3x3(int p[9], int m = 9);
private:
};
And here the content of the class description :
Matrice3x3::Matrice3x3(int u) {
n = u*u;
}
Matrice3x3::Matrice3x3(int p[9] , int m){
n = m;
t = p;
}
And i get this error :
In constructor 'Matrice3x3::Matrice3x3(int*, int)':
incompatible types in assignment of 'int*' to 'int [9]'
t = p;
^
I just don't see where i said one of the [] was a pointer...
thanks for answering!
You cannot copy arrays like this. You should copy them element by element or use memcpy.
In general case it is better to use standard library for containers (std::vector in this case). You should have strong reason to prefer C-style array to standard container.
Well, if you really want fixed sized arrays, use C++11's std::array<> (Boost has a definition as well, for pre C++11). You can allocate it as std::array < int, 9 > and then pass it around as an object. You can also use the size() member function to get the number of elements (although its hardcoded in the type) and it has other member functions (such as begin() and end()) which make it look like a std container, so you can use std's algorithms on it as well. Basically, a wrapper around a fixed sized array. Of course you can pass by value of reference.
There are two ways (that I know) of assigning one vector to another:
std::vector<std:string> vectorOne, vectorTwo;
// fill vectorOne with strings
// First assign method
vectorTwo = vectorOne;
// Second assign method
vectorTwo.assign( vectorOne.begin(), vectorOne.end() );
Is there really difference within those methods or they are equal in terms of efficiency and safety when performed on very big vectors?
They're pretty much equivalent. The reason for the second is
that you might have types which need (implicit) conversion:
std::vector<int> vi;
std::vector<double> vd;
// ...
vd.assign( vi.begin(), vi.end() );
Or the type of the container might be different:
vd.assign( std::istream_iterator<double>( file ),
std::istream_iterator<double>() );
If you know that both of the containers are the same type, just
use assignment. It has the advantage of only using a single
reference to the source, and possibly allowing move semantics in
C++11.
The second form is generic, it works with any iterator types, and just copies the elements from the source vector.
The first form only works with exactly the same type of vector, it copies the elements and in C++11 might also replace the allocator by copying the allocator from the source vector.
In your example the types are identical, and use std::allocator which is stateless, so there is no difference. You should use the first form because it's simpler and easier to read.
They are equivalent in this case. [and C++03 standaerd]. The difference will be however if vectorTwo contains elements before assignment. Then
vectorTwo = vectorOne; // use operator=
// Any elements held in the container before the call
// are either assigned to or destroyed.
vectorTwo.assign() // any elements held in the container
// before the call are destroyed and replaced by newly
// constructed elements (no assignments of elements take place).
assign is needed because operator= takes single right-hand operand so assign is used when there is a need for a default argument value or range of values. What assign does could be done indirectly by first creating suitable vector and then assigning that:
void f(vector<Book>& v, list<Book>& l){
vector<Book> vt = (l.begin(), l.end());
v = vt;
}
however this can be both ugly and inefficient (example has been taken from Bjarne Stroustrup "The C++...")
Also note that if vector is not of the same type then there is also need for assign which allows implicit conversion:
vector<int> vi;
vector<double> vd;
// ...
vd.assign( vi.begin(), vi.end() );
Can someone explain this code please? how is it that the function bar accepts a reference to the first element of the vector?
jintArray arry;
std::vector<int> foo = GetIntegerArray(env, arry);
bar(&foo[0])
where the protoytpe of bar is
bar(int* array)
This is valid as long as the template type isn't bool. The C++ vector type specifies that the vector elements are consecutive in memory like that so that you can do exactly this.
The reason why it doesn't work with bool is due to template specialization. Where the bools are compressed down to a bitfield.
http://en.wikipedia.org/wiki/Vector_%28C%2B%2B%29#vector.3Cbool.3E_specialization
how is it that the function bar accepts a reference to the first element of the vector?
This seems to be the source of the confusion. The expression &foo[0] is not a reference to the first element, but rather a pointer. operator[] is overloaded in the vector class to obtain a reference (or const-reference), and applying & will obtain the address of the object.
Yes. Just make sure the vector is not empty, or &foo[0] would be an error. C++11 introduced the std::vector<T>::data() function that does not have this problem.
Also, returning a vector by value is usually not a good idea. You might want to use an output iterator or a vector reference parameter in GetIntegerArray, so you would call it like this:
std::vector<int> foo;
GetIntegerArray(env, arry, back_inserter(foo));
or
std::vector<int> foo;
GetIntegerArray(env, arry, foo);
When you use std::vector<int>, it is guaranteed that all the element are created in contiguous memory. As such, when you write &v[0] it returns the pointer to the first element, and from this you can go the next element by writing &v[0]+1, and so on.
By the way, if you want to traverse through all elements or a section of elements, then a better interface for bar would be this:
void bar(int *begin, int *end)
{
for ( ; begin != end; ++begin)
{
//code
}
}
So you can call like this:
bar(&foo[0], &foo[0] + foo.size());//process all elements
bar(&foo[0], &foo[0] + foo.size()/2);//process first half elements
bar(&foo[0], &foo[0] + N); //process first N elements(assumingN <=foo.size())
bar(&foo[0]+foo.size()/2, &foo[0]+foo.size());//process second half elements
A const int * and an int *const are very different. Similarly with const std::auto_ptr<int> vs. std::auto_ptr<const int>. However, there appears to be no such distinction with const std::vector<int> vs. std::vector<const int> (actually I'm not sure the second is even allowed). Why is this?
Sometimes I have a function which I want to pass a reference to a vector. The function shouldn't modify the vector itself (eg. no push_back()), but it wants to modify each of the contained values (say, increment them). Similarly, I might want a function to only change the vector structure but not modify any of its existing contents (though this would be odd). This kind of thing is possible with std::auto_ptr (for example), but because std::vector::front() (for example) is defined as
const T &front() const;
T &front();
rather than just
T &front() const;
There's no way to express this.
Examples of what I want to do:
//create a (non-modifiable) auto_ptr containing a (modifiable) int
const std::auto_ptr<int> a(new int(3));
//this works and makes sense - changing the value pointed to, not the pointer itself
*a = 4;
//this is an error, as it should be
a.reset();
//create a (non-modifiable) vector containing a (modifiable) int
const std::vector<int> v(1, 3);
//this makes sense to me but doesn't work - trying to change the value in the vector, not the vector itself
v.front() = 4;
//this is an error, as it should be
v.clear();
It's a design decision.
If you have a const container, it usually stands to reason that you don't want anybody to modify the elements that it contains, which are an intrinsic part of it. That the container completely "owns" these elements "solidifies the bond", if you will.
This is in contrast to the historic, more lower-level "container" implementations (i.e. raw arrays) which are more hands-off. As you quite rightly say, there is a big difference between int const* and int * const. But standard containers simply choose to pass the constness on.
The difference is that pointers to int do not own the ints that they point to, whereas a vector<int> does own the contained ints. A vector<int> can be conceptualised as a struct with int members, where the number of members just happens to be variable.
If you want to create a function that can modify the values contained in the vector but not the vector itself then you should design the function to accept iterator arguments.
Example:
void setAllToOne(std::vector<int>::iterator begin, std::vector<int>::iterator end)
{
std::for_each(begin, end, [](int& elem) { elem = 1; });
}
If you can afford to put the desired functionality in a header, then it can be made generic as:
template<typename OutputIterator>
void setAllToOne(OutputIterator begin, OutputIterator end)
{
typedef typename iterator_traits<OutputIterator>::reference ref;
std::for_each(begin, end, [](ref elem) { elem = 1; });
}
One big problem syntactically with what you suggest is this: a std::vector<const T> is not the same type as a std::vector<T>. Therefore, you could not pass a vector<T> to a function that expects a vector<const T> without some kind of conversion. Not a simple cast, but the creation of a new vector<const T>. And that new one could not simply share data with the old; it would have to either copy or move the data from the old one to the new one.
You can get away with this with std::shared_ptr, but that's because those are shared pointers. You can have two objects that reference the same pointer, so the conversion from a std::shared_ptr<T> to shared_ptr<const T> doesn't hurt (beyond bumping the reference count). There is no such thing as a shared_vector.
std::unique_ptr works too because they can only be moved from, not copied. Therefore, only one of them will ever have the pointer.
So what you're asking for is simply not possible.
You are correct, it is not possible to have a vector of const int primarily because the elements will not assignable (requirements for the type of the element contained in the vector).
If you want a function that only modifies the elements of a vector but not add elements to the vector itself, this is primarily what STL does for you -- have functions that are agnostic about which container a sequence of elements is contained in. The function simply takes a pair of iterators and does its thing for that sequence, completely oblivious to the fact that they are contained in a vector.
Look up "insert iterators" for getting to know about how to insert something into a container without needing to know what the elements are. E.g., back_inserter takes a container and all that it cares for is to know that the container has a member function called "push_back".