Dynamically allocating an array of objects fails - c++

I'm able to create a dynamically sized array of integers like this:
int *cacheL2 = new int[L2/B2];
and I'm also able to create an object of type Data like this:
Data one(12,12);
and now I want a dynamically sized array of Data:
Data * vlaObj = new Data[L2/B2];
but it does not work...
Also, if you can tell me how to get hashes working for c++ that would be great. I was looking for examples, but everything just says #include "hash_map" however when I try to use the library it cant seem to find any of them.

#include <vector>
// ...
std::vector<Data> v;
v.emplace_back( 12, 12 );

There is no reason to not use STL containers here. It is recommended to use std::vector instead of raw pointers:
#include <vector>
//...
std::vector<Data> vlaObj(L2/B2);
vlaObj.push_back(one)
Edit: BTW is there any chance that L2 or even B2 value can be 0?

One of the most probable reasons why Data* arr = new Data[len]; wouldn't work is because type Data has no default constructor, i.e. Data::Data().
But no matter whether Data has a default constructor or not, it's not a good idea to try to create an array like this anyway. Once you dynamically allocate it with new[] you commit yourself to take care of ugly memory management connect with it. It's much better idea to use one of STL containers such as std::vector (#include <vector> required) that will take care of memory management for you.
Then you have several options:
std::vector<Data> v; // option 1
v.reserve(len);
// in loop:
v.push_back(Data(x, y)); // there could be different values
std::vector<Data> v2(len); // option 2
std::vector<Data> v3(len, Data(12,12)); // option 3
First option will fit almost any situation. It prepares the chunk of memory big enough to hold len elements and then you can just fill v in convenient but still very efficient manner. Option 2 requires Data to have default constructor, which is solved by option 3 that uses your custom constructor to construct elements.
All mentioned options result in std::vector object with automatic storage duration being created. Note that all elements are stored in a continuous block of memory, so you can use &v[0] to initialize the pointer to its first element and work with it in a same way you would work with dynamically allocated array.

Related

Is it possible to extract data from std::vector without copying it? (and make the vector forget it)

I have a std::vector<byte> object and I want to extract data from it without copying.
It may contain megabytes of data. So, if I copy data I would lose performance.
Is it possible to extract the data from the vector and make it forget about data, that is, that it doesn't free memory for the data after destruction?
Hope for your help!
Thanks in advance!
P.S: extract in this case means just get a raw pointer to the data and make vector forget about it (i.e don't free the memory after destruction)
No, It is not possible to extract part of data from vector as far as I know.
It is not compatible with structure of vector that provides its data in a continuous part of memory. std::vector memory is continues, so if it was possible to move part of its memory to another place, you need to shift reminder of memory to keep it continuous. It will be a huge burden itself.
I personally suggest to pass main vector by pointer/reference and use required parts directly as needed.
If you need to move whole data of std::vector to another place, you can just use std::move() to do so. You can even use std::swap() to swap contents of 2 vector together.
I have a std::vector object and I want to extract data from it without copying
You can move the entire contents of a vector ... into a different vector.
Or you can swap (the contents of) two vectors.
std::vector<byte> v = get_a_big_vector();
std::vector<byte> w = std::move(v); // now w owns the large allocation
std::vector<byte> x;
std::swap(x,y); // now x owns the large allocation, and w is empty
That's it. You can't ask a vector to release its storage, and you can't somehow "take" just a portion of a contiguous allocation without affecting the rest.
You can move-assign some sub-range of elements, but that's only different to copying if the elements are some kind of object with state stored outside the instance (eg, a long std::string).
If you really need to take just a sub-range and let the rest be deallocated, then a vector isn't really the right data type. Something like a rope is designed for this, or you can just split your single contiguous vector into a vector of 1Mb (or whatever) chunk indirections. This is actually something like a deque (although you can't steal chunks from std::deque either).
I think the best way is to use an object orineted approach. You can abstract byte data inside a class with other information like a flag to make them to be skipped or forget:
class Data
{
public:
Data(byte d)
{
data = d;
forget = false;
}
byte data;
bool forget;
}
Then just add to the vector pointers to data like
vector<Data*> data;
data.push_back(new Data(1));
data.push_back(new Data(2));
// and so on
You can extract data without copying just getting the pointers to specific element of the array:
Data *d = data[index];
d->forget = true;
You can use the forget flag to make it forgettable. Of course you have to manage the forget flag yourself when searching the vector. You can use the std::find_if with a lamba expression for this porpouse.
Keep in mind you have to free memory when data is not used any more.

How can I build a vector whose data is pointed to an array, and is this possible for unified memory?

We know that if we have a vector like
std::vector<int> a_vector;
and this vector has elements, we can have the array of elements from
int *the_array= a_vector.data();
My question is: How can we do the opposite?
int the_array[5]={1,2,3,4,5};
std::vector<int> a_vector;
a_vector.data=the_array; //this does not seem to work
To clarify, I don't wish to copy the values , nor create an array *from * the values but have them in the same memory area.
Also , why am I asking this?
I would like to have this original array, in a managed (unified) area of memory
__device__ __managed__ int the_array[5];
and build the vector to point there.
we can have the array of elements from
What we get from std::vector::data is a pointer to the first element.
My question is: How can we do the opposite?
a_vector.data=the_array; //this does not seem to work
No. Only way for a vector to take ownership of an array like that is from another vector of same type.
Being able to construct a vector with already allocated memory would somewhat defeat the RAI design principle which is propably the reason it's isn't part of the std::vector API.
If all you need is a nice modern C++ interface to your allocated memory, span would be the right choice. You don't need to wait for NVIDIA to implement C++20, but could use the gsl-lite implementation of span which provides __host__ __device__ member functions such that you can use their span inside (or as arguments to) kernels as well.
If you want an actual container (not a view), which manages the memory (also allocates it), Thrust would be the obvious choice. While it was possible before to use their device_vector with a custom allocator, nowadays they provide a universal_vector for unified memory.

Is it possible to have a std::vector of struct with a fexible array member?

I have a struct with a flexible array member that I need to use.
struct Record
{
uint32_t length;
Data contents[];
};
I'm able to initialize this and use it by doing something like this: (it would also work with malloc or any other dynamic allocation)
vector<Data> members;
vector<uint8_t> buffer;
Record myRecord;
buffer.resize(sizeof(Record) + members.size() * sizeof(Data));
myRecord = *(reinterpret_cast<Record*>(buffer.data());
myRecord.length = static_cast<uint32_t>(members.size());
// copy members to myRecord.contents
That works just fine. But now I need to have an interface that operates on batches of Record, and I have been trying to use an std::vector for this. Then problems start appearing, and I'm guessing it's because std::vector arranges all elements contiguously on memory, and since sizeof(Record) won't take into account the size of the contents (each vector element will hold only 4 bytes, instead of 4 bytes + size_of_contents * sizeof(Data)), the vector elements are actually sharing memory and then each element starts overwriting the contents of the previous element. Does that make sense?
If this really is the problem, I was wondering if there's any way to "force" the vector to allocate a specific size for each element (instead of whatever sizeof returns for the element's type). That way I could make sure that each vector element would have enough size. If that's not possible, is there an alternative solution? Maybe a different container that would allow me to do so? Please keep in mind that I do need to use the struct as it's defined (I would love to just replace the whole thing for a vector but unfortunately that's not possible)
Your principle problem is this:
myRecord = *(reinterpret_cast<Record*>(buffer.data());
That's simply overwriting the data in a stack variable. That does not change the address of myRecord to suddenly point to buffer.data(). Which means when you later do myRecord.contents[...] = ..., you're going to be trashing the stack.
What you almost certainly intended was:
Record *myRecord = (reinterpret_cast<Record*>(buffer.data());
Then you would have a pointer to memory managed by buffer, which would have sufficient storage for the myRecord->contents array.
You cannot treat Record like a value type. As far as C++'s object model is concerned, it's not a value type. It cannot be copied or moved like most C++ types. You can only manipulate it through a pointer/reference to the specific allocation you use here.
That being said, using a vector to manage the storage for your Record* like this is really weird. It'd be better to use a unique_ptr, since resizing the allocation would be a really bad idea.
std::unique_ptr<char[]> storage = new char[sizeof(Record) + (members.size() * sizeof(Data))];
This also prevents the system from initializing the memory, since you're going to overwrite it anyway.
I was wondering if there's any way to "force" the vector to allocate a specific size for each element (instead of whatever sizeof returns for the element's type).
No. vector manages a contiguous array of elements of the same type. And in C++, all objects of the same type have the same size.

2D arrays and dynamic arrays

I have a class which just contains a 1D array of set size (17): However this array needs to be for every monitor that a user has and I am unsure whether to simply set say and array of size 10 limiting the user, or whether to try a more dynamic approach.
Excerpt from ScreenArray.h:
private:
unsigned long pixelArray[17];
I would like advise to which method(s) will work best for my problem and how would I go about constructing / allocating and accessing it?
EDIT: The array (Or the 2D part of the array) preferably dynamic to the size of the monitors currently connected. This contains the 1D array of set size 17.
As UnholySheep stated out, vector is a great tool to use in this situation:
Variable size;
Out of range protection;
Automatic memory management;
...
The only drawback I see may be a loss in performance, but because your vector is so small, you won't even be able to measure it, so this doesn't count.
You can use it like so:
// You'll need this one
#include <vector>
// Create you vector
// Replace TYPE with the type of it's members.
std::vector< TYPE > pixelArray;
// Add members to it
pixelArray.push_back( MEMBER );
// Access it as usual
pixelArray[n];

Dynamic memory allocation, C++

I need to write a function that can read a file, and add all of the unique words to a dynamically allocated array. I know how to create a dynamically allocated array if, for instance, you are asking for the number of entries in the array:
int value;
cin >> value;
int *number;
number = new int[value];
My problem is that I don't know ahead of time how many unique words are going to be in the file, so I can't initially just read the value or ask for it. Also, I need to make this work with arrays, and not vectors. Is there a way to do something similar to a push_back using a dynamically allocated array?
Right now, the only thing I can come up with is first to create an array that stores ALL of the words in the file (1000), then have it pass through it and find the number of unique words. Then use that value to create a dynamically allocated array which I would then pass through again to store all the unique words. Obviously, that solution sounds pretty overboard for something that should have a more effective solution.
Can someone point me in the right direction, as to whether or not there is a better way? I feel like this would be rather easy to do with vectors, so I think it's kind of silly to require it to be an array (unless there's some important thing that I need to learn about dynamically allocated arrays in this homework assignment).
EDIT: Here's another question. I know there are going to be 1000 words in the file, but I don't know how many unique words there will be. Here's an idea. I could create a 1000 element array, write all of the unique words into that array while keeping track of how many I've done. Once I've finished, I could provision a dynamically allocate a new array with that count, and then just copy the words from the initial array to the second. Not sure if that's the most efficient, but with us not being able to use vectors, I don't think efficiency is a huge concern in this assignment.
A vector really is a better fit for this than an array. Really.
But if you must use an array, you can at least make it behave like a vector :-).
Here's how: allocate the array with some capacity. Store the allocated capacity in a "capacity" variable. Each time you add to the array, increment a separate "length" variable. When you go to add something to the array and discover it's not big enough (length == capacity), allocate a second, longer array, then copy the original's contents to the new one, then finally deallocate the original.
This gives you the effect of being able to grow the array. If performance becomes a concern, grow it by more than one element at a time.
Congrats, after following these easy steps you have implemented a small subset of std::vector functionality atop an array!
As you have rightly pointed out this is trivial with a Vector.
However, given that you are limited to using an array, you will likely need to do one of the following:
Initialize the array with a suitably large size and live with poor memory utilization
Write your own code to dynamically increase the size of the array at run time (basically the internals of a Vector)
If you were permitted to do so, some sort of hash map or linked list would also be a good solution.
If I had to use an array, I'd just allocate one with some initial size, then keep doubling that size when I fill it to accommodate any new values that won't fit in an array with the previous sizes.
Since this question regards C++, memory allocation would be done with the new keyword. But what would be nice is if one could use the realloc() function, which resizes the memory and retains the values in the previously allocated memory. That way one wouldn't need to copy the new values from the old array to the new array. Although I'm not so sure realloc() would play well with memory allocated with new.
You can "resize" array like this (N is size of currentArray, T is type of its elements):
// create new array
T *newArray = new T[N * 2];
// Copy the data
for ( int i = 0; i < N; i++ )
newArray[i] = currentArray[i];
// Change the size to match
N *= 2;
// Destroy the old array
delete [] currentArray;
// set currentArray to newArray
currentArray = newArray;
Using this solution you have to copy the data. There might be a solution that does not require it.
But I think it would be more convenient for you to use std::vectors. You can just push_back into them and they will resize automatically for you.
You can cheat a bit:
use std::set to get all the unique words then copy the set into a dynamically allocated array (or preferably vector).
#include <iterator>
#include <set>
#include <iostream>
#include <string>
// Copy into a set
// this will make sure they are all unique
std::set<std::string> data;
std::copy(std::istream_iterator<std::string>(std::cin),
std::istream_iterator<std::string>(),
std::inserter(data, data.end()));
// Copy the data into your array (or vector).
std::string* words = new std::string[data.size()];
std::copy(data.begin(), data.end(), &words[0]);
This could be going a bit overboard, but you could implement a linked list in C++... it would actually allow you to use a vector-like implementation without actually using vectors (which are actually the best solution).
The implementation is fairly easy: just a pointer to the next and previous nodes and storing the "head" node in a place you can easily access to. Then just looping through the list would let you check which words are already in, and which are not. You could even implement a counter, and count the number of times a word is repeated throughout the text.