C array of objects that allow for dynamic allocation - c++

If I have a class with dynamic allocaton like std::vector. How much sense does it make to create an array with elements of that object?
I tested the following:
std::vector<int> array[2];
array[0].push_back(10);
array[0].push_back(20);
array[0].push_back(30);
array[1].push_back(40);
array[1].push_back(50);
array[1].push_back(60);
for (auto x : array[0]) {
std::cout << x << std::endl;
}
for (auto x : array[1]) {
std::cout << x << std::endl;
}
Which outputs the values correctly. However is this actually undefined behavior? Array elements are located contiguously in memory. When a std::vector object is initialized without specifying size, it doesn't allocate any memory. So when we create an array with two elements, is any memory allocated at all? When we then add new elements to std::vector are we writing outside of the array bounds?

There is no undefined behavior here.
How much sense does it make to create an array with elements of that object?
This is entirely up to you, and your design considerations. It's perfectly fine to have an array of vectors.
So when we create an array with two elements, is any memory allocated at all?
Yes, memory for the array is allocated.
When we then add new elements to std::vector are we writing outside of the array bounds?
std::vector allocates memory dynamically. A default-constructed vector may or may not allocate memory. This is implementation-dependent. Internally, the vector is probably just holding pointers.
Some implementations may be smarter than this, by switching from a fixed number of elements with no dynamic allocation to using dynamic allocation if the requirements exceed that. std::string implementations commonly do this, by repurposing the internal pointer storage to hold string data instead.
Note that if you are pushing some number of elements onto a new vector, it's good practice to call reserve on that vector to avoid unnecessary reallocations as it grows.

An object of the type std::vector<int> has a fixed size that depends on its implementation.
Consider the following demonstrative program.
#include <iostream>
#include <vector>
int main()
{
std::vector<int> array[2];
std::cout << "sizeof( std::vector<int> ) = "
<< sizeof( std::vector<int> )
<< '\n';
std::cout << "sizeof( array = "
<< sizeof( array )
<< '\n';
std::cout << '\n';
array[0].push_back(10);
array[0].push_back(20);
array[0].push_back(30);
array[1].push_back(40);
array[1].push_back(50);
array[1].push_back(60);
std::cout << "sizeof( std::vector<int> ) = "
<< sizeof( std::vector<int> )
<< '\n';
std::cout << "sizeof( array = "
<< sizeof( array )
<< '\n';
}
Its output might look like
sizeof( std::vector<int> ) = 24
sizeof( array = 48
sizeof( std::vector<int> ) = 24
sizeof( array = 48
When you are adding new elements to the vectors their sizes are not changed and correspondingly the array size also is not changed.
The program is well-formed.
The class template std::vector contains as its data member a pointer to a memory where it places its elements. If there is no enough memory the vector reallocates it. But the size of an object itself of the vector type does not depend on the reallocated memory.

Related

Pass array to function without so it would not change original array no matter what

I have a function that performs some magic on the array that I am passing. But the original array should be intact. Unfortunately it is changing its content based on what is happening in the array.
Can you help me, please?
Function:
void test(int* array) {
array[0] = 1; // EDIT: Added missing line
std::cout << "Inside: " << array[0] << endl;
}
int main() {
int *testArray = new int[1];
testArray[0] = 0;
std::cout<<testArray[0]<<endl;
test(testArray);
std::cout << "Outside: " << testArray[0] << endl;
}
Current result is:
0
Inside: 1
Outside: 1
Result I would want to have:
0
Inside: 1
Outside: 0
Is this possible?
It sounds like you want to pass array by value not by reference. You are passing pointer to a first element here. So, any changes which you perform to that array inside that function will be reflected to original array.
The other problem is you haven't posted fair amount of code regarding the problem you want to solve. I am assuming you want functionality like this.
See live demo here.
#include <iostream>
void test(const int* array) {
array[0]=1;
std::cout << "Inside: " << array[0] << std::endl;
}
int main() {
int *testArray = new int[1];
testArray[0] = 0;
std::cout<<testArray[0]<<std::endl;
test(testArray);
std::cout << "Outside: " << testArray[0] << std::endl;
delete[] testArray;
}
Compiler will give you following errors:
Error(s):
source_file.cpp:4:13: error: read-only variable is not assignable
array[0]=1;
~~~~~~~~^
1 error generated.
You should not use new[] to allocate dynamic arrays in C++. 99% of the time you should be using std::vector If you want dynamic array in C++.
Avoid using C compatibility features...
void test( std::array<int, 1> a )
{
a[0] = 1; // fine
std::cout << "Inside: " << a[0] << endl;
};
int main()
{
std::array<int, 1> testArray;
testArray[0] = 0;
std::cout<<testArray[0]<<endl;
test(testArray);
std::cout << "Outside: " << testArray[0] << endl;
}
If you need the size determined at runtime, use std::vector instead of std::array.
EDIT: As others have pointed out, it seems like you want to either pass the array by value instead of by reference, thus copying the elements of the array and modifying only the copy, or you want to avoid modifying any part of the array altogether. I'll elaborate on both parts a bit more:
In C++, there is near to no distinction between arrays and pointers. Note that both your variable testArray and your parameter array are pointers to the beginning of an array. If you use array to modify any part of the underlying array, what you actually do is modify the memory are that is described by both testArray and array. If you don't want to modify any part of the array at all, it would be helpful to use the const qualifier, as Destructor already wrote in his answer. If you however want to keep the original array but still want to make some modifications inside the function, the following still applies:
To keep the array from being modified, the only general way that works is to copy all of its elements by creating a new array of the same size, copying all elements from the input array to the copy and then working only on the copy, which should be deleted after the function has finished.
My personal answer:
I would recommend that you look into some of C++'s data structures, especially std::vector. If you pass it by value (not by reference), vector takes care of all the necessary copy operations I just described and in all cases, you can use it in the same way as an array, while it provides lots of additional features (i.e. dynamic size, deletion and insertion of elements, simplified iteration, ...).

C++ Growth of containers containing containers?

If I have a std::vector<std::set<int>>. The vector will reallocate if you insert past its capacity. In the case where you have another resizable type inside the vector, is the vector only holding a pointer to the said type?
In particular I want to know about how memory is allocated if a vector is holding an arbitrary type.
std::vector<int> a(10); //Size will be sizeof(int) * 10
std::vector<std::set<int>> b(10);
b[0] = {0, 0, 0, 0, 0, 0, 0, .... }; //Is b's size effected by the sets inside?
C++ objects can only have one size, but may include pointers to arbitrarily sized heap memory. So, yes, container objects themselves generally include a pointer to heap memory and probably don't include any actual items. (The only typical exception is string types, which sometimes have a "small string optimization" that allows string objects to contain small strings directly in the object without allocating heap memory.)
The memory that any vector will allocate "by itself" will always be sizeof(element_type) * vector.size().
The vector can only allocate memory for element data that is visible at compile time. It doesn't care about any allocations done by the element class.
Think of a vector as an array on steroids. Like an array, a vector consists of a contiguous block of memory where all elements have the same size. To fullfill this requirement it must know at compile time how big each element will be.
Imagine a std::set to have these member variables:
struct SomeSet
{
size_t size;
SomeMagicInternalType* data;
};
So no matter how data will be allocated at runtime, the vector only allocates memory per element for what it knows at compile time:
sizeof(SomeSet::size) + sizeof(SomeSet::data)
Which would be 4 + 4 on a 32-bit machine.
Consider this example:
#include <iostream>
#include <vector>
int main() {
std::vector<int> v;
std::cout << sizeof(v) << "\n";
std::cout << v.size() << "\n";
v.push_back(3);
std::cout << sizeof(v) << "\n";
std::cout << v.size() << "\n";
}
The exact number may differ, but I get as output:
24
0
24
1
The size (size=size of the object) of a vector does not change when you add an element. The same is true for a set, thus a vector<set> does not need to reallocate if one of its elements adds or removes an element.
A set does not store its elements as members, otherwise sets with different number of elements would be different types. They are stored on the heap and as such do not contribute to the size of the set directly.
A std::vector<T> holds objects of type T. When it gets resized it copies or moves those objects as needed. A std::vector<std::set<int>> is no different; it holds objects of type std::set<int>.

What's the correct way to work with bounded arrays in C++?

I'm trying to understand how bounded arrays work in C++. I need to have a quick length method to return the size of my bounded array. In Java I would do something like that:
int[] array = new int[10];
System.out.println(array.length); // 10
System.out.println(array[5]); // 0
array[5] = 11;
System.out.prinltn(array[5]); // 11
If possible I would like to use an object array (i.e. a class implementing an array functionality) instead of pointers. Would I be correct to say that it feels much more natural to use an object array instead of a memory pointer to work with arrays?
C++ has a class std::array<type, size> which is basically just a wrapper for stack-allocated arrays. C++ also has a class std::vector<type> which is a wrapper for heap-allocated arrays (like what you're used to in Java) but which also has ArrayList-like functionality.
In your case, writing code which is logically and semantically identical to yours is:
std::vector<int> array(10, 0); //EDIT: I added the second parameter because I don't think all implementations zero the memory when allocating it. This ensures that the memory is zeroed before use, like it would be in Java.
std::cout << array.size() << std::endl;
std::cout << array[5] << std::endl;
array[5] = 11;
std::cout << array[5] << std::endl;
Though, I wouldn't name the variable array, since that could be confusing.

How to declare an array with a variable number of elements [C++]?

How do I [dynamically?] declare an array with an 'i' number of elements?
By using a container of the standard-library instead, most commonly std::vector<>.
Other solutions contain manual allocation and deallocation of memory and are probably not worth the effort.
You could use std::vector<T>. It works like
std::vector<int> a;
a.push_back(2); // add 2 to the array
a.push_back(4);
You could go on and on, and you won't need to worry about memory allocation issues.
You have to use pointers.
Example:
float *ptrarray = new float [10];
Basically, type * pointername = new type [i];
And don't forget to clean your memory:
delete [] ptrarray;
Or it will be reserved until the program ends.
Create a Dynamically Sized Array
std::size_t N = 10;
SomeType *a = new SomeType[N];
for (auto i=0; i<N; ++i) {
std::cout << a[i] << std::endl;
}
delete [] a;
A C++ array is a pointer to a contiguous chunk of memory containing a specific type. This snippet allocates space for an array of 10 SomeType instances, constructs the array which initializes each object using the default constructor, iterates over the array, prints out each element, and then deallocates the memory by calling delete [].
Key Points:
you are required to call delete [] to deallocate the array. The array form is required to ensure that the destructor is called on each object.
after allocation, there is no way to recover the size of the array.
you can iterate over the array by index (or pointer)
This is not the way to do what you want, keep reading.
Using a vector
std::size_t N = 10;
std::vector<SomeType> v(10);
for (auto iter=v.begin(); iter!=v.end(); ++iter) {
std::cout << *iter << std::endl;
}
This snippet uses std::vector which manages a contiguous block of memory for you. Note the usage of an iterator to walk over the vector instead of using indexing. Vectors do support direct indexing so the for loop used in the previous example would work here as well.
for (auto i=0; i<v.size(); ++i) {
std::cout << v[i] << std::endl;
}
Using an iterator is the best practice and idiomatic though using a for loop may not be but I digress.
Key Points:
memory management is automatic in the case of a vector
you can append using push_back
a vector knows how many elements are in it -- call v.size() to get the number of elements
iteration is performed using the iterators returned from v.begin() and v.end()
Just use std::vector. If you need raw access to the underlying pointer, then use &v[0] or v.data() but don't do that unless you need to. Also, don't use std::auto_ptr for arrays. You will be tempted to but don't do it.

How do I access the internal contiguous buffer of a std::vector and can I use it with memcpy, etc?

How can I access the contiguous memory buffer used within a std::vector so I can perform direct memory operations on it (e.g. memcpy)? Also, it is safe to perform operations like memcpy on that buffer?
I've read that the standard guarantees that a vector uses a contiguous memory buffer internally, but that it is not necessarily implemented as a dynamic array. I figure given that it is definitely contiguous, I should be able to use it as such - but I wasn't sure if the vector implementation stored book-keeping data as part of that buffer. If it did, then something like memcpying the vector buffer would destroy its internal state.
In practice, virtually all compilers implement vector as an array under the hood. You can get a pointer to this array by doing &somevector[0]. If the contents of the vector are POD ('plain-old-data') types, doing memcpy should be safe - however if they're C++ classes with complex initialization logic, you'd be safer using std::copy.
Simply do
&vec[0];
// or Goz's suggestion:
&vec.front();
// or
&*vec.begin();
// but I don't know why you'd want to do that
This returns the address of the first element in the vector (assuming vec has more than 0 elements), which is the address of the array it uses. vector storage is guaranteed by the standard to be contiguous, so this is a safe way to use a vector with functions that expect arrays.
Be aware that if you add, or remove elements from the vector, or [potentially] modify the vector in any way (such as calling reserve), this pointer could become invalid and point to a deallocated area of memory.
You can simply do:
&vect[0]
The memory is guaranteed contiguous so its safe to work with it with C library functions such as memcpy. However, you shouldn't persist pointers into the contiguous data because vector resizes may reallocate and copy the memory to a different location. IE the following would be bad:
std::vector<char> charVect;
// insert a bunch of stuff into charVect
...
char* bufferPtr = &charVect[0];
charVect.push_back('a'); // potential resize
// Now bufferPtr may not be valid since the resize may have moved
// the vectors contents
bufferPtr[0] = 'f'; // **CRASH**
&myvec[0]
But note that using memcpy is really only applicable if this is a vector of PODs or primitive types. Doing direct memory manipulation of anything else leads to undefined behaviour.
The simplest way is to use &v[0], where v is your vector. An example:
int write_vector(int fd, const std::vector<char>& v) {
int rval = write(fd, &v[0], v.size());
return rval;
}
Yes - since the standard guarantees contiguous placement of the vector's internal data, you can access a pointer to the first element in the vector via:
std::vector<int> my_vector;
// initialize...
int* arr = &my_vector[0];
While you can safely read the right amount of data from the underlying storage, writing there may not happen to be a good idea, depending on the design.
vlad:Code ⧴ cat vectortest.cpp
#include <vector>
#include <iostream>
int main()
{
using namespace std;
vector<char> v(2);
v.reserve(10);
char c[6]={ 'H', 'e', 'l', 'l', 'o', '\0' };
cout << "Original size is " << v.size();
memcpy( v.data(), c, 6);
cout << ", after memcpy it is " << v.size();
copy(c, c+6, v.begin());
cout << ", and after copy it is " << v.size() << endl;
cout << "Arr: " << c << endl;
cout << "Vec: ";
for (auto i = v.begin(); i!=v.end(); ++i) cout << *i;
cout << endl;
}
vlad:Code ⧴ make vectortest
make: `vectortest' is up to date.
vlad:Code ⧴ ./vectortest
Original size is 2, after memcpy it is 2, and after copy it is 2
Arr: Hello
Vec: He
vlad:Code ⧴
So if you are writing past the size(), then the new data is not accessible by class methods.
You can account for that and ensure the size is enough (e.g. vector<char> v(10)), but do you really want to make software where you are fighting the standard library?