unique_ptr<TStringList []> dsts(new TStringList[5]) fail - c++

MyEnvironment:
C++ Builder XE4
I am trying to use array of TStringList using unique_ptr<>.
Following didn't give any error:
unique_ptr<int []> vals(new int [10]);
On the other hand, following shows error:
unique_ptr<TStringList []> sls(new TStringList [10]);
The error is 'access violation at 0x000000000: read of address 0x0000000'.
For TStringList, can't I use array of unique_ptr<>?

It isn't a unique_ptr issue: your attempt fails because you are trying to create an array of actual TStringList object instances instead of an array of pointers to TStringList instances (for further details you can take a look at How to create an array of buttons on Borland C++ Builder and work with it? and Quality Central report #78902).
E.g. You'll get an access violation even if you try:
TStringList *sls(new TStringList[10]);
(pointer to a dynamic array of size 10 and type TStringList).
You have to manage a pointer to a dynamic array of type TStringList *. Using std::unique_ptr:
std::unique_ptr< std::unique_ptr<TStringList> [] > sls(
new std::unique_ptr<TStringList>[10]);
sls[0].reset(new TStringList);
sls[1].reset(new TStringList);
sls[0]->Add("Test 00");
sls[0]->Add("Test 01");
sls[1]->Add("Test 10");
sls[1]->Add("Test 11");
ShowMessage(sls[0]->Text);
ShowMessage(sls[1]->Text);
Anyway, if the size is known at compile time, this is a better choice:
boost::array<std::unique_ptr<TStringList>, 10> sls;
(also take a look at Is there any use for unique_ptr with array?)

Related

C++ Initialise emtpy array based on template defined length and type

Good whatever part of the day you're reading this!
I've been trying to implement my own version of an std::deque-like container. I thought it would be possible to use templates to customise the size and type of the inner array 'blocks', but I can't seem to get the syntax right. Or at least I think what I'm doing is somehow possible.
template<typename T, int ChunkSize>
class ChunkList
{
public:
ChunkList()
{
T first[ChunkSize] = new T[ChunkSize];
// error: array must be initialized with a brace-enclosed initializer
m_ChunkPointers.push_back(first);
}
private:
// store pointers to the chunks
std::vector<T[]> m_ChunkPointers;
};
int main()
{
ChunkList<int, 4> cl = new ChunkList<int, 4>();
}
// compiled with g++ on a windows x64 machine
I found a Stack Overflow answer relating to the brace-enclosed initializer but I don't know how to initialize those with the template syntax.
The only other solution I can think is is using something like malloc(sizeof(T) * ChunkSize) and then casting that to an T[] or something.
Either way any help/advice would be greatly appreciated, always happy to learn new things!
PS: Even if there is a way more efficient solution I'd still like to know if there is a way to make templates behave the way I intend to here, or rather why this isn't valid.
You are already using std::vector why not a proper container for the chunks too?!?
template<typename T, int ChunkSize>
struct ChunkList {
ChunkList() : m_Chunks(1) {}
private:
std::vector<std::array<T,ChunkSize>> m_Chunks;
};
// store pointers to the chunks - You do not want to store pointers, you want to store arrays. You attempted to store them on the heap, but that complication is totally unnecessary, because they are of fixed size and std::vector does already manage its elements in dynamically allocated memory.
We have a few problems here.
1: In main you wrote ChunkList<int, 4> cl = new ChunkList<int, 4>();
This will not work because new will return a ChunkList* not a ChunkList you need to write ChunkList<int, 4>* cl = new ChunkList<int, 4>(); or ChunkList<int, 4> cl{}; depending on the hact if you need an object or a pointer to an object
2:std::vector<T[]> m_ChunkPointers; declares a vector of empty arrays. I think you menat to write std::vector<T*> m_ChunkPointers; storeing pointers (to the start of the arrays.)
3: T first[ChunkSize] = new T[ChunkSize]; needs to be T *first = new T[ChunkSize];
You mixed together the T x[N]; sintax and the T*x=new T[N]; syntax. the first will create an array on the stack the second will create one array, living until the end of the function on the heap, living until you detete it.
Note: Welcome to C++. In C++ the variables the object themself, not referances/pointers. You need to manage the lifetimes of the objects living in the heep. If you don't want to delete every object you used I suggest to take a look on unique_ptr and shared_ptr

Creating a global array of structs

For a project I am working on I need to have a global array of entry structs. I am having trouble though because I can't allocate memory until while running my program I determine the size of a file. The overall goal of this project is to create a word reference. So far how I am doing it is:
struct info{
//stores the specific character
std:: string c;
//stores the amount of times a word has come up in the file
float num;
}
info info_store[];
This project is to learn about arrays so I need to use an array
You can:
- use new/delete[]
info* p_array=new info[100]; // create an array of size 100
p_array[10].num; // member access example
delete[] p_array; // release memory
- use std::unique_ptr
std::unique_ptr<info[]> array(new info[size]);
-> The advantage is that your memory is automatically released when array is destroyed (no more delete[])
First of all, use std::vector or any other STL container.
Second, you can use dynamic arrays.
auto length = count_structs(file);
auto data = new info[length];
Something like this. Then just fill this array.
Ohh, and make sure you have delete [] data to prevent memory leaks.

How to replace Malloc with std::vector

I have some memory issues in my program so i have tried to convert the mallocs i have into vectors but have been unsuccessful.
The code i currently have:
midimhandle_t dimensions[3], *dimensions_new;
dimensions_new = (midimhandle_t *) malloc(sizeof(midimhandle_t) * 3);
free(dimensions_new);
The vector replacement that does not work:
midimhandle_t dimensions[3], *dimensions_new;
std::vector<midimhandle_t> dimensions_new(sizeof(midimhandle_t) * 3)
However when i try to run my code with the replacement code i get the following error
error: cannot convert ‘std::vector<midimension*>’ to ‘midimension**’
So my question are:
Are the creation of the vector wrong or is there something else i have to take into account?
I'd do it this way:
std::array<midimhandle_t, 3> dimensions;
std::vector<midimhandle_t> dimensions_new(3);
The first is a fixed-size, uninitialized array. It stores its values directly inside, so if it's created on the stack the values will be too.
The second is an adjustable-size, default (value) initialized vector. It stores its values on the heap.
Please replace this:
midimhandle_t dimensions[3], *dimensions_new;
std::vector<midimhandle_t> dimensions_new(sizeof(midimhandle_t) * 3);
with simply:
midimhandle_t dimensions[3];
std::vector<midimhandle_t> dimensions_new(3);
Yes, your means of creating the vector is wrong, and you need to take other things into account.
Assuming your original C code looks something like
void some_function()
{
midimhandle_t *dimensions_new;
dimensions_new = (midimhandle_t *) malloc(sizeof(midimhandle_t) * 3);
// do something here
free(dimensions_new);
}
A rough equivalent using a std::vector would be
void some_function()
{
std::vector<midimhandle_t> dimensions_new(3); // create vector with 3 elements
// do something here
// the vector will cease to exist as the function returns
}
Another thing to account for is that a std::vector is actually a C++ (templated) class, so supports a different set of operations (e.g. to access elements) than a pointer to an array allocated using malloc() - which means, depending on what // do something here represents, that you will still get compilation errors. You'll need to read the documentation for std::vector to learn how to use it effectively.

Select a random object from an array of objects

I'd like to implement a function that selects a random object from an array of objects and returns it to me. It should be something like (in C++ instead of psuedocode):
getRandomObject(objectList) {
return objectList[int(random(length of objectList))];
}
My current code looks like this, but doesn't seem to work:
//definition of random selector
object getRandomObject(Object* objectList) {
return objectList[int(ofRandom(0, sizeof(objectList)))];
};
//create a pointer for the listOfObjects
object* listOfObjects;
//create an empty object to put the randomly selected object in
object randomObject;
//later in the code, populate the array:
object* listOfObjects[] = {
new Object(),
new Object(),
new Object()
};
//select random object
randomObject = getRandomObject(listOfObjects);
But this seems to return a segmentation fault. A few problems I've noticed:
sizeof() returns the size of the pointer in getRandomObject, not the size of the array. is there a good way to get the size of the array? It might involves not using a float* pointer for the array. Is this a good use case for vectors?
I think that much of the problem lies in how I'm creating my arrays, and not so much in how I'm selecting the random object from them. I'm relatively new to C++ (coming from a Java background), so much of pointers / references / memory management in general is new to me.
thanks!
I see one definite problem and one possible one. The definite problem is that sizeof(objectList) returns the size of the objectList pointer, which will be 4 or 8 on most platforms. It does not return the number of elements in the array, objectList. Either pass in the length of the array or use std::vector or std::array.
The second possible problem relates to ofRandom. Make sure that ofRandom(a,b) returns numbers >= a, but strictly < b. If it returns values <= b, then you'll need to us ofRandom(0, objectVector.size() - 1). Typically, functions like this are written to return values strictly < b, but you should check.
C++ has an array template class that you may want to consider using. Check out the documentation here:
http://www.cplusplus.com/reference/array/array/
This type has a method, size(), that will return the length of the array.
When the sizeof operator is applied to an array, it yields the total
number of bytes in that array, not the size of the pointer represented
by the array identifier.
Quote
So you take the space alocated for your whole array and divide by the memory need just for one element: sizeof(objectList) / sizeof(*objectList).
Mr Fooz noticed issues that cause a segfault.
Other compilation issues are:
listOfObjects is declared with 2 different types: object* and object*[3] while getRandomObject expects a type Object*.
listOfObjects[] contains elements of type object* while getRandomObject reads elements of type Object and returns object.

Qt C++ - QList<float**> type not allowed

I would like to pass a list of float** arguments to some method which is working with C-syle and float** only (but we consider we can have a QList<> as arguments type).
I tried with
QList< float** > list_ = new QList< float** >();
but this is not working. What should i use instead ? What would be for instead Qt container for a list of 2D matrices ?
thanks
You are using a java like syntax (or c# or others)
In C++ it should be either
QList<float**> *list_ = new QList<float**>() ; //Pointer to a heap allocated list, Closer to what you wanted to do i think. NEED TO CALL "delete list_" once you are done with it.
or
QList<float**> list_; //List on the stack, more c++ish, destroyed once it goes out of scope.