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.
Related
I want to understand the usage of the "<DataType>" in C++.
As far as I read about, it is the syntax used for templates, which uses the specified data type for specialization of function or class instantiation.
Coming from python, I understand that all data types are by definition a class (correct me if it does not apply for C++), so if you look for the int implementation in python, you will find:
class int:
#overload
def __new__(cls: Type[_T], x: str | bytes | SupportsInt | SupportsIndex | _SupportsTrunc = ...) -> _T: ...
...
Which constructor is overloaded based in arguments. So why in C++ it does not use (dataType) instead of <dataType> and overload the constructor based on the type of the arguments?
Also, can I safely state that every time <DataType> appears, it is surely a template there?
some examples:
std::vector<int> x;
std::vector< std::vector<int> >& someVar;
cv::Mat opencvMat;
int x = static_cast<int>(opencvMat.at<float>(i, 3) * frameWidth);
I'll use your examples:
std::vector<int> x;
x is a vector (dynamic-length array) that contains ints.
std::vector< std::vector<int> >& someVar;
someVar is a reference to a vector of vectors. The inner vectors holds ints. This would be a common way to make a reference to a two-dimensional dynamic array, where each row could have a different number of columns.
int x = static_cast<int>(opencvMat.at<float>(i, 3) * frameWidth);
This is how you do various styles of cast. I'll break it into two:
opencvMat.at<float>(i, 3)
I don't use this library, but the at method is probably a template, and it means you're going to receive a float.
The static_cast forces the calculated value to an int without a compiler warning for loss of precision.
As you've figured out, this is all related to templates, and you'll see templates are defined using <>. For instance:
template <class ObjectType>
class Foo:
public:
ObjectType value;
};
Foo<std::string> myFoo;
In this case, myFoo.value is a string.
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.
I have trouble using std::begin() and std::end() (from the iterator library) with c-style array parameters.
void SetOrigin(const double i_point[3]) {
Vector v;
std::copy(
std::begin(i_point),
std::end(i_point),
v.begin());
this->setOrigin(v);
}
This results in the following error with Visual Studio 2010 (and similar for end):
error C2784: '_Ty *std::begin(_Ty (&)[_Size])' : could not deduce template argument for '_Ty (&)[_Size]' from 'const double []'
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\xutility(995) : see declaration of 'std::begin'
Changing the parameter to non-const gives same result.
Trying to specify the parameter as
...
std::begin<const double, 3>(i_point),
std::end<const double, 3>(i_point),
...
Gives:
error C2664: '_Ty *std::begin<const double,3>(_Ty (&)[3])' : cannot convert parameter 1 from 'const double []' to 'const double (&)[3]'
Is it just not possible to use std::begin on array parameters because they decay to pointers? Is there a trick to get around this or is it best just to not use the iterator functions on array parameters?
Yes, std::begin and std::end can work with parameters that are C style arrays.
The trick is in passing a parameter that's a C style array. When you specify a 1D array as a normal parameter to a normal function, its type is silently adjusted from "array of T" to "pointer to T". When you call that function, what gets passed isn't the array (as an array), but a pointer to the first element of the array.
It is, however, possible to pass an array by reference to a function template:
template <class T, size_t N>
void function(T (&array)[N]) {
// function body here
}
In this case, where you're passing an actual array (albeit, by reference) rather than a pointer, you can use std::begin and std::end perfectly well. For example:
template <class T, size_t N>
T sum(T (&array)[N]) {
return std::accumulate(std::begin(array), std::end(array), T());
}
Now passing an array is trivial, such as:
int array[] = {1, 2, 3, 4};
auto total = sum(array);
std::begin and std::end themselves are (or at least can be) implemented similarly to sum--the array is passed by reference, so they can look something like this:
template <class T, size_t N>
T *begin(T (&array)[N]) {
return array;
}
template <class T, size_t N>
T *end(T (&array)[N]) {
return array + N;
}
Note that although these were added to the standard more recently, they don't require any particularly tricky use of templates, so the implementation above should work fine with a plain old C++98 compiler (and, if memory serves, even with pre-standard compilers such as VC++ 6).
First off, note that the parameter declaration const double i_point[3] is absolutely equivalent to const double* i_point. That is, the function takes any pointer to double const independent of the number of elements pointed to. As a result, it doesn't know the size and std::begin() and std::end() can't deduce the size (well, std::begin() doesn't really need to deduce the size anyway).
If you really want to use std::begin() and std::end() you need to pass an array with three element or a reference to such a beast. Since you cannot pass arrays by value, your best bet is to pass it by reference:
void SetOrigin(double const (&i_point)[3]) {
// ...
}
This function only accepts arrays with exactly three elements as arguments: You cannot pass a pointer to three doubles or a part of a bigger array. In return, you can now use std::begin() and std::end().
void SetOrigin(const double i_point[3])
is as same as
void SetOrigin(const double i_point[])
or
void SetOrigin(const double *i_point)
So, std::begin and std::end can not accept it. In C++ you can not pass an array but as a pointer or reference. If it's a pointer then it doesn't carry any information of passed array.
Your alternatives are std::vector or std::array.
Have you looked at std::array?
It works better with other STL components
While not directly answering your question (it has already been answered sufficiently by M M. and Dietmar Kühl), you appear to want to initialize some std::vector in this function. That said, why not just have:
std::vector v;
std::copy(std::begin(x), std::end(x), std::back_inserter(v));
// or std::copy(x, x + 3, std::back_inserter(v));
Instead of a function call to your function that is trying to do this?
Alternatively, you could write you function like this:
template<typename RandomIterator>
void SetOrigin(RandomIterator start, RandomIterator end)
{
std::vector<int> v;
std::copy(start, end, std::back_inserter(v));
SetOrigin(v);
}
and then call it using:
double xyz[3];
SetOrigin(std::begin(xyz), std::end(xyz));
I would like to create a map where the key is an int, and the value is a list of arrays (int[][]).
I tried this :
const int R = 4, C = 5;
std::map<int, std::list<int[R][C]> > s;
but it won't compile and I don't understand why ... (R and C are parameter of the program but do not change during execution).
Arrays are not copy constructable or copy assignable, which an element of a standard container must be. Your code will compile as is, but the array type breaks the requirements for the standard containers and you'll run into undefined behaviour. You can't have an std::list<int[R][C]>. However, C++11 provides a nice new compile-time constant sized std::array for your pleasure:
typedef std::array<std::array<int, C>, R> array_2d;
typedef std::list<array_2d> array_list;
std::map<int, array_list> s;
Otherwise, other alternatives are to use std::vector instead of std::array (preferred), or to have a std::list of int** and dynamically allocate your 2D arrays.
However, I'd consider a bit of a rethink of your design. Is this really the structure you want? Should any of the data be grouped into a struct?
When I do something like this:
int my_array[5] = {1, 2, 3, 4, 5};
for (int &x : my_array) {
x *= 2;
}
C++11 obviously knows that my array only has 5 elements. Is this information stored somewhere in the my_array object?
If so, is there any good reason why it is not made available to me as a developer (or is it?!?!?)? It seems that a lot of the world's problems would be solved if C++ devs always knew the bounds of the arrays they're dealing with.
This is simply something that the language requires to work, and the compiler must implement. Obviously the complete type of my_array is int[5] (i.e. the size is part of the type), so this information is readily available.
Contrary to popular belief, there is no use of the free std::begin()/std::end() functions in play, although those would naively seem to be able to do the trick (but there's a catch involving ADL that would break this approach).
It is available - you can define begin and end on arrays in standard C++. The size of the array is encoded in the type.
The general method is to use references to arrays.
Here's an example size function:
template<typename T, size_t N>
size_t array_size(T (& const)[N])
{
return N;
}
No, it's not part of the object. But it's part of the type. That's what the 5 in the array declaration is. However, this won't work:
void f(int arr[5]) {
for(int& x: arr) {
// whatever
}
}
because the name of the array here decays into a pointer to its first element, that is, the argument declaration is equivalent to int *arr which has no size information.