I'm moving from Objective-C to C++ and am not sure what vectors are. I've read documentation about them, I'm not quite clear though. How would you explain C++ vectors using Objective-C analogies?
They're pretty similar to NSMutableArrays but vector is a template class and so can be instanciated for any (standard-template-library compatible) type. NSArrays always hold NSObjects.
That is, assuming you mean std::vector.
They're like NSMutableArrays but can hold any data type - pointer or not. However, each vector can only ever hold one type at a time. Also as it's C++ there are fewer functions e.g. no plist loading/saving.
A C++ vector (presumably you mean something like std::vector) is basically an NSArray, except it holds any type you want (which is the template parameter, e.g. a std::vector<int> holds ints). Of course, it doesn't do memory management (which NSArray does), because arbitrary types aren't retain-counted. So for example a std::vector<id> would be rather inappropriate (assuming Obj-C++).
NSArray is a wrapper around CFArray. CFArray can store any data type.
I don't know much about C++, but it sounds like CFArray can do everything you'd use a vector for? When creating a CFArray you give it a CFArrayCallBacks pointer, which contains any logic that is specific to the data type being stored.
Of course, you could always just rename your Obj-C file to *.mm, and mix C++ into your objective-c.
http://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFArrayRef/Reference/reference.html
In C++ an Array is basically just a pointer to a contiguous block of data---a series of elements. It offers no built-in methods, or higher functionality.
int intArr[] = {0,1,2,3};
is the same as
int *intArr = (int *)malloc(4*sizeof(int));
for(int i = 0; i < 4; i++) { intArr[i] = i; }
A vector (std::vector), on the other hand, is a container for elements (basically like an array) which also offers additional built in methods (see: http://www.cplusplus.com/reference/stl/vector/) such as
vector<int> intArr;
for(int i = 0; i < 4; i++) { intArr.push_back(i); }
// this yields the same content; i.e. intArr = {0,1,2,3}
Both arrays and vectors can be used on any type of objects, int, double, 'MySpacePirateWizardClass' etc. The big bonus of vectors is the additional functionality from built-in functions like:
int arrSize = intArr.size(); // vector also includes useful information
int *firstElement = intArr.begin(); // methods for creating pointers to elements
intArr.delete(0); // modify elements
intArr.insert(0, 2); // modify vector
// now: intArr = {2,1,2,3}
etc etc.
When I know I'm not going to be short on space (or looking at massive amounts of data), I always use vectors because they're so more convenient (even just the size() method alone is reason enough).
Think about vectors as advanced arrays.
If you are new to C++, this page will be your best friend:
http://www.cplusplus.com/reference/stl/vector/
Related
I was recently learning to use struct datatype in c++. I know how the basics of struct datatype work and how to manipulate its variables. But I was wondering how would I determine the end of struct datatype array. For example consider the code below:
struct PersonDetails
{
string name, address;
int age, number;
}
Now in c++ program I create an array of struct type as follows:
PersonDetails Data[500];
Now consider that I have 30 records in data array and I have to display these records by looping through data array's index. So how would I determine that I have to loop through only first 30 indexes as the data is only stored in these indexes. As in char array we compare all indexes with '\0' to determine the end of array. Then what method will we use for Data[] array?
An edit that I have no idea about Vectors and the project i am working on requires me to use basics of c++(functions, control structures, loops, etc.).
It's not feasible.
For char[], back in times of C standardization, developers agreed to use \0 (integer value 0) as a special character marking end-of-string. Everything works as long as everyone is following this convention (i.e. both standard library functions and developers using those functions).
If you wanted to have such a convention for your type, you could just write down "Data object with both strings empty and both ints equal to 0 is array terminator", but you would have to follow this convention. You'd have to write functions that would stop processing array upon finding such an object. You'd have to make sure that in every array there is at least one such object.
Instead
You should use std::vector<Data> which can automatically accomodate for any number of Data objects and will now precisely how many of them are currently stored (using size() method)
or
use std::array<Data, 30>, which can store exactly 30 objects and you can assume all of them are valid objects.
IMHO the correct way to solve this is to not use a C-style array, but instead use a std::array or std::vector that knows it's .size().
Iterating a std::vector or std::array is trivial:
for (const auto& element : Data_array) {
// Do something with the array element
}
See also:
https://en.cppreference.com/w/cpp/container/array
https://en.cppreference.com/w/cpp/container/vector
https://en.cppreference.com/w/cpp/language/for
https://en.cppreference.com/w/cpp/language/range-for
The simplest solution is to just have a separate variable specifying how many array elements are filled in.
PersonDetails Data[500];
int numPersons = 0;
Data[0].name = ... ;
Data[0].address = ...;
Data[0].age = ...;
Data[0].number = ...;
numPersons = 1;
Data[1].name = ... ;
Data[1].address = ...;
Data[1].age = ...;
Data[1].number = ...;
numPersons = 2;
...
Then you use that variable when looping through the array.
for (int i = 0; i < numPersons; ++i)
{
// use Data[i] as needed...
}
I don't really agree using std::array makes any difference.
The problem you currently have doesn't occur in whether we have such an element in the container, but whether the element we are inspecting useful.
Consider the example you gave, for an array of chars, we simply check whether one of the elements is \0 to decide whether or not we should halt the iteration.
How does that work? The ramaining elements, of course, default initialized to be \0, they exist, but of no use.
Similarly, you can check, in this example, whether
name.empty()
Or, in order to avoid any possible exception, as mentioned in the comment section, do this:
add user-defined constructor to the class ( or struct, they are same actually.) which initialize age to -1 and then check if age == -1.
because it's impossible for a people not having any name, that means, you have not assign to any of the remaining elements. Thus, stop iteration.
As a supplement, using std::vector makes sense, but if that isn't a option for you for the time being, you don't need to consider it.
I recently found this won't work in my global CUDA C++ code that I plan to compile and later to be called in Matlab:
int M = 10; float V[M];
or if I were to import M value from the matlab host code.
But this works:
float V[10];
I was told there exists a function called new that I can use to avoid this problem, but I read online and am still quite confused how to use this new function, and it seems only to apply to host code, is that right? If so, it won't apply to my case then, since my host code is in matlab. Is this a way to get around this, so that I don't have to change vector lengths one by one? Thank you!
I don't know anything about MATLAB or CUDA, but your problem is in C++. Arrays declared like that must have sizes fixed at compile-time.
Solution 1: Fix the size
Declare your variable M const. These are equivalent:
int const M = 10;
const int M = 10;
The compiler would then know that it can assume these variables will always have the same value no matter how you run the program.
Solution 2: C-style dynamic allocation
Dynamic allocation with new and delete. Arrays allocated on the abstract section of memory called the "free-store" (rather than on the "stack", like those arrays you have) can determine their sizes on the fly. You use it like this:
float * V = new V[M]; //V is a pointer to some freestore memory
//You use it and pass it like you would a normal array:
V[2] = 5.5;
int x = some_func(V);
//But after you're done, you should manually free the memory
delete [] V; //don't forget the [], since you used [] in the allocation
I don't recommend this, because of the possiblity of forgetting to delete the memory.
Solution 3: Automatic memory management with C++'s vector
In C++, the work of memory management can be hidden behind structures called classes.
#include<vector>
using std::vector;
vector<float> V(M); //V is a vector of floats, with initial size M
//You use it like a normal array
V[2] = 5.5;
//But to pass it as an array, you need to pass a pointer to the first element
int x = some_func(&V[0]); //read as &(V[0]): pass in the address of V[0]
Solution 3b: CUDA-compatible vector
Thrust is a C++ template library for CUDA based on the Standard Template Library (STL). Thrust allows you to implement high performance parallel applications with minimal programming effort through a high-level interface that is fully interoperable with CUDA C.
http://docs.nvidia.com/cuda/thrust/#vectors
Conclusion
If you're using fixed sizes, I recommend solution 1. If you're using sizes determined during runtime, I recommend vector.
(By the way, when you pass an ordinary array to a function, you are actually passing a pointer to the first element, NOT the array. The name of the array is automatically converted to a pointer type.)
I need to create a large two dimensional array of objects. I've read some related questions on this site and others regarding multi_array, matrix, vector, etc, but haven't been able to put it together. If you recommend using one of those, please go ahead and translate the code below.
Some considerations:
The array is somewhat large (1300 x 1372).
I might be working with more than one of these at a time.
I'll have to pass it to a function at some point.
Speed is a large factor.
The two approaches that I thought of were:
Pixel pixelArray[1300][1372];
for(int i=0; i<1300; i++) {
for(int j=0; j<1372; j++) {
pixelArray[i][j].setOn(true);
...
}
}
and
Pixel* pixelArray[1300][1372];
for(int i=0; i<1300; i++) {
for(int j=0; j<1372; j++) {
pixelArray[i][j] = new Pixel();
pixelArray[i][j]->setOn(true);
...
}
}
What's the right approach/syntax here?
Edit:
Several answers have assumed Pixel is small - I left out details about Pixel for convenience, but it's not small/trivial. It has ~20 data members and ~16 member functions.
Your first approach allocates everything on stack, which is otherwise fine, but leads to stack overflow when you try to allocate too much stack. The limit is usually around 8 megabytes on modern OSes, so that allocating arrays of 1300 * 1372 elements on stack is not an option.
Your second approach allocates 1300 * 1372 elements on heap, which is a tremendous load for the allocator, which holds multiple linked lists to chunks of allocted and free memory. Also a bad idea, especially since Pixel seems to be rather small.
What I would do is this:
Pixel* pixelArray = new Pixel[1300 * 1372];
for(int i=0; i<1300; i++) {
for(int j=0; j<1372; j++) {
pixelArray[i * 1372 + j].setOn(true);
...
}
}
This way you allocate one large chunk of memory on heap. Stack is happy and so is the heap allocator.
If you want to pass it to a function, I'd vote against using simple arrays. Consider:
void doWork(Pixel array[][]);
This does not contain any size information. You could pass the size info via separate arguments, but I'd rather use something like std::vector<Pixel>. Of course, this requires that you define an addressing convention (row-major or column-major).
An alternative is std::vector<std::vector<Pixel> >, where each level of vectors is one array dimension. Advantage: The double subscript like in pixelArray[x][y] works, but the creation of such a structure is tedious, copying is more expensive because it happens per contained vector instance instead of with a simple memcpy, and the vectors contained in the top-level vector must not necessarily have the same size.
These are basically your options using the Standard Library. The right solution would be something like std::vector with two dimensions. Numerical libraries and image manipulation libraries come to mind, but matrix and image classes are most likely limited to primitive data types in their elements.
EDIT: Forgot to make it clear that everything above is only arguments. In the end, your personal taste and the context will have to be taken into account. If you're on your own in the project, vector plus defined and documented addressing convention should be good enough. But if you're in a team, and it's likely that someone will disregard the documented convention, the cascaded vector-in-vector structure is probably better because the tedious parts can be implemented by helper functions.
I'm not sure how complicated your Pixel data type is, but maybe something like this will work for you?:
std::fill(array, array+100, 42); // sets every value in the array to 42
Reference:
Initialization of a normal array with one default value
Check out Boost's Generic Image Library.
gray8_image_t pixelArray;
pixelArray.recreate(1300,1372);
for(gray8_image_t::iterator pIt = pixelArray.begin(); pIt != pixelArray.end(); pIt++) {
*pIt = 1;
}
My personal peference would be to use std::vector
typedef std::vector<Pixel> PixelRow;
typedef std::vector<PixelRow> PixelMatrix;
PixelMatrix pixelArray(1300, PixelRow(1372, Pixel(true)));
// ^^^^ ^^^^ ^^^^^^^^^^^
// Size 1 Size 2 default Value
While I wouldn't necessarily make this a struct, this demonstrates how I would approach storing and accessing the data. If Pixel is rather large, you may want to use a std::deque instead.
struct Pixel2D {
Pixel2D (size_t rsz_, size_t csz_) : data(rsz_*csz_), rsz(rsz_), csz(csz_) {
for (size_t r = 0; r < rsz; r++)
for (size_t c = 0; c < csz; c++)
at(r, c).setOn(true);
}
Pixel &at(size_t row, size_t col) {return data.at(row*csz+col);}
std::vector<Pixel> data;
size_t rsz;
size_t csz;
};
std::array is vastly superior to the C arrays. And even if I want to interoperate with legacy code, I can just use std::array::data(). Is there any reason I would ever want an old-school array?
Unless I've missed something (I've not followed the most recent changes in the standard too closely), most of the uses of C style arrays still remain. std::array does allow static initialization, but it still won't count the initializers for you. And since the only real use of C style arrays before std::array was for statically initialized tables
along the lines of:
MyStruct const table[] =
{
{ something1, otherthing1 },
// ...
};
using the usual begin and end template functions (adopted in
C++11) to iterate over them. Without ever mentionning the size, which the compiler determines from the number of initializers.
EDIT: Another thing I forgot: string literals are still C style arrays; i.e. with type char[]. I don't think that anyone would exclude using string literals just because we have std::array.
No. To, uh, put it bluntly. And in 30 characters.
Of course, you need C arrays to implement std::array, but that's not really a reason that a user would ever want C arrays. In addition, no, std::array is not less performant than a C array, and has an option for a bounds-checked access. And finally, it is completely reasonable for any C++ program to depend on the Standard library- that's kind of the point of it being Standard- and if you don't have access to a Standard library, then your compiler is non-conformant and the question is tagged "C++", not "C++ and those not-C++ things that miss out half the specification because they felt it inappropriate.".
Seems like using multi-dimensional arrays is easier with C arrays than std::array. For instance,
char c_arr[5][6][7];
as opposed to
std::array<std::array<std::array<char, 7>, 6>, 5> cpp_arr;
Also due to the automatic decay property of C arrays, c_arr[i] in the above example will decay to a pointer and you just need to pass the remaining dimensions as two more parameters. My point is it c_arr is not expensive to copy. However, cpp_arr[i] will be very costly to copy.
As Sumant said, multi-dimensional arrays are a lot easier to use with built in C-arrays than with std::array.
When nested, std::array can become very hard to read and unnecessarily verbose.
For example:
std::array<std::array<int, 3>, 3> arr1;
compared to
char c_arr[3][3];
Also, note that begin(), end() and size() all return meaningless values when you nest std::array.
For these reasons I've created my own fixed size multidimensional array containers, array_2d and array_3d. They are analogous to std::array but for multidimensional arrays of 2 and 3 dimensions. They are safer and have no worse performance than built-in multidimensional arrays. I didn't include a container for multidimensional arrays with dimensions greater than 3 as they are uncommon. In C++0x a variadic template version could be made which supports an arbitrary number of dimensions.
An example of the two-dimensional variant:
//Create an array 3 x 5 (Notice the extra pair of braces)
fsma::array_2d <double, 3, 5> my2darr = {{
{ 32.19, 47.29, 31.99, 19.11, 11.19},
{ 11.29, 22.49, 33.47, 17.29, 5.01 },
{ 41.97, 22.09, 9.76, 22.55, 6.22 }
}};
Full documentation is available here:
http://fsma.googlecode.com/files/fsma.html
You can download the library here:
http://fsma.googlecode.com/files/fsma.zip
The C-style arrays that are available in C++ are actually much less versatile than the real C-arrays. The difference is, that in C, array types can have runtime sizes. The following is valid C code, but it can neither be expressed with C++ C-style arrays nor with the C++ array<> types:
void foo(int bar) {
double tempArray[bar];
//Do something with the bar elements in tempArray.
}
In C++, you would have to allocate the temporary array on the heap:
void foo(int bar) {
double* tempArray = new double[bar];
//Do something with the bar elements behind tempArray.
delete[] tempArray;
}
This cannot be achieved with std::array<>, because bar is not known at compile time, it requires the use of either C-style arrays in C++ or of std::vector<>.
While the first example could relatively easily be expressed in C++ (albeit requiring new[] and delete[]), the following cannot be achieved in C++ without std::vector<>:
void smoothImage(int width, int height, int (*pixels)[width]) {
int (*copy)[width] = malloc(height*sizeof(*copy));
memcpy(copy, pixels, height*sizeof(*copy));
for(y = height; y--; ) {
for(x = width; x--; ) {
pixels[y][x] = //compute smoothed value based on data around copy[y][x]
}
}
free(copy);
}
The point is, that the pointers to the line arrays int (*)[width] cannot use a runtime width in C++, which makes any image manipulation code much more complicated in C++ than it is in C. A typical C++ implementation of the image manipulation example would look like this:
void smoothImage(int width, int height, int* pixels) {
int* copy = new int[height*width];
memcpy(copy, pixels, height*width*sizeof(*copy));
for(y = height; y--; ) {
for(x = width; x--; ) {
pixels[y*width + x] = //compute smoothed value based on data around copy[y*width + x]
}
}
delete[] copy;
}
This code does precisely the same calculations as the C code above, but it needs to perform the index computation by hand wherever the indices are used. For the 2D case, this is still feasible (even though it comes with a lot of opportunities to get the index calculation wrong). It gets really nasty in the 3D case, though.
I like writing code in C++. But whenever I need to manipulate multidimensional data, I really ask myself whether I should move that part of the code to C.
May be the std::array is not slow. But I did some benchmarking using simple store and read from the std::array;
See the below benchmark results (on W8.1, VS2013 Update 4):
ARR_SIZE: 100 * 1000
Avrg = Tick / ARR_SIZE;
test_arr_without_init
==>VMem: 5.15Mb
==>PMem: 8.94Mb
==>Tick: 3132
==>Avrg: 0.03132
test_arr_with_init_array_at
==>VMem: 5.16Mb
==>PMem: 8.98Mb
==>Tick: 925
==>Avrg: 0.00925
test_arr_with_array_at
==>VMem: 5.16Mb
==>PMem: 8.97Mb
==>Tick: 769
==>Avrg: 0.00769
test_c_arr_without_init
==>VMem: 5.16Mb
==>PMem: 8.94Mb
==>Tick: 358
==>Avrg: 0.00358
test_c_arr_with_init
==>VMem: 5.16Mb
==>PMem: 8.94Mb
==>Tick: 305
==>Avrg: 0.00305
According to the negative marks, the code I used is in the pastebin (link)
The benchmark class code is here;
I don't know a lot about benchmarkings... My code may be flawed
to implement something like std::array
if you don't want to use the STL or can't
For performance
Sorry if the title is not clear but I ll explain now my problem. I am new in C++.
I have created a class in C++. Instances of that class are the input of the program and they have to be stored in an array to perform the calculations. The problem is that the number of instances of that class that have to be defined by the user is fixed for a single run but can vary from run to run. Here an example:
#include <<blablah>blahblah>
int main()
{
int number_of_instances = 3;
MyClass first_instance(one_parameter_1, another_parameter_1);
MyClass second_instance(one_parameter_2, another_parameter_2);
MyClass third_instance(one_parameter_3, another_parameter_3);
///////////////////
NOW I HAVE TO STORE ALL THREE IN AN ARRAY LIKE
MyClass array[number_of_instances] = {first_instance, second_instance, third_instance};
THE PROBLEM IS THAT I DO NOT KNOW BEFORE HAND HOW MANY OF THEM ARE THE USER IS GOING TO INPUT
///////////////////
performCalculations(array);
return 0;
}
Thanks a lot in advance.
The typical C++ solution is to use a vector.
vector<MyClass> v;
v.push_back(first_instance); //add an already instantiated object to the end of the vector
v.push_back(second_instance);
v.push_back(third_instance);
You won't have to worry about memory management and you are able to access the vector like you would a normal array:
v[0].classMember
You can also add items to the vector in a loop if needed like so:
for(int i = 0; i < 5; i++){
v.push_back( MyClass(i, param2) );
}
And all the objects will be destructed when the vector goes out of scope if you're storing the objects directly in the vector.
One of the downsides to storing the objects directly in the vector is passing the vector as a parameter to a function. This will be a slow operation since the vector (and all the objects it holds) will have to be copied.
If you know the number of instances before you read them all in then you can allocate an array on the heap using new[]. (Don't forget to delete[] them when you've finished.) Note that this requires that the object have a default constructor.
you should use std::vector in this case rather than a built-in array.
#include <vector>
...
std::vector<MyClass> v = {first_instance, second_instance, third_instance};
...
v.push_back(fourth_instance);
If you don't know how many elements the array will contain, I would use a std::vector instead of a plain array as the vector will grow to accommodate the additional elements.
What you want is the Vector class from the standard template library, it behaves like an array but it will re-size itself if you fill it's internal allocation. If you do not need random access to it (i.e. use the [] opperator) you may want to use the List class instead. If you use List you will need to create an enumerator to step through it.
use std::vector<MyClass>, vector template can be found in <vector> header. YOu must learn a little bit to code well, before coding use any of online available c++ FAQs