How to dynamically store address of a QVector<T> in another QVector<QVector<T>*>? - c++

I am working with large amounts of data, something like 100,000 double values, being gathered every 100 milliseconds or so. I have to store 25 or even more of these generated data in my software at any given time. Both, the data length on each acquisition as well as the number of acquisitions varies depending on the current situation. I do not want to store my data as QVector<QVector<double>> because QVector stores data in adjacent memory locations and each addition of QVector<double> to QVector<QVector<double>> results in the entire thing being copied to a new location given, resulting in huge lags (especially if there is already 20 QVector<double> present and I am adding the 21st one to it).
My solution is to store the given data as QVector<QVector<double>*> i.e. each data acquisition I am just storing the address to the QVector for the current acquisition. However, I want it to be stored in QVector<QVector<double>*> independently i.e. as long as I don't clear the pointer I am able to access the data. I am unable to figure out how to do this. I have tried multiple methods. Let's say I declare QVector<QVector<double>*> myVec; in my .h file and I use a function to new add data to it on each acquisition like this (below function is just for testing, that's why I am creating data inside the function):
void MainWindow::addData()
{
myVec << &QVector<double>(0) // Creating a new empty vector and storing it's location
*myVec[0] << 2.7 << 3.4 << 4.5;
}
This doesn't work, most of the time it throws an exception, and a few times it just shows some garbage value.
void MainWindow::addData()
{
QVector<double> tempVec; // Create a temprory vector
tempVec << 2.7 << 3.4 << 4.5;
myVec << &tempVec;
}
This also doesn't work, of course, because tempVec is destroyed as soon as addData() is exited.
void MainWindow::addData()
{
QVector<double> tempVec; // Create a temprory vector
tempVec << 2.7 << 3.4 << 4.5;
myVec << &QVector(tempVec);
}
I thought this would work as I am not storing the address of tempVec but rather copying tempVec in a new QVector and assigning its address to myVec, but it is also throwing an exception.
Is there any way I can store QVector purely as pointers inside another QVector ?

You're storing addresses to objects that are then destroyed. That means your vector of pointers contains dangling pointers:
void MainWindow::addData()
{
myVec << &QVector<double>(0);
// the temporary vector is destroyed here and myVec contains a
// dangling pointer
*myVec[0] << 2.7 << 3.4 << 4.5;
}
I'm surprised your compiler even accepts this code, since taking the address of a temporary should be a compilation error. Naming the temporary allows it to compile, but it's not any better, since you still get a dangling pointer:
void MainWindow::addData()
{
QVector<double> tempVec(0);
myVec << &tempVec;
*myVec[0] << 2.7 << 3.4 << 4.5;
} // <-- tempVec is destroyed here, so you get a dangling pointer
If you store a pointer to an object, you need to make sure this object still exists whenever you access that pointer.
One way around this would be to allocate each vector with new before storing its address. But then you need to remember to delete it when you no longer need the pointers. Instead of that, you can use a smart pointer instead. std::unique_ptr in this case would do the job, but unfortunately QVector cannot store non-copyable elemens. So you'd need std::shared_ptr. This way, you don't need to store the pointers anywhere else but myVec:
#include <memory>
QVector<std::shared_ptr<QVector<double>>> myVec;
// ...
void MainWindow::addData()
{
myVec << std::make_shared<QVector<double>>(0);
*myVec[0].get() << 2.7 << 3.4 << 4.5;
}
If you don't absolutely require QVector and can do with std::vector instead, I'd recommend that, since it can store std::unique_ptr elements just fine:
#include <memory>
#include <vector>
std::vector<std::unique_ptr<QVector<double>>> myVec;
// ...
void MainWindow::addData()
{
myVec.push_back(std::make_unique<QVector<double>>(0));
*myVec[0].get() << 2.7 << 3.4 << 4.5;
}
If you really need to store raw pointers and can't use smart pointers, then I'm afraid you need to manage the pointed-to objects yourself by allocating them with new and then once you're done with myVec and no longer need it, clean up with delete:
QVector<QVector<double>*> myVec;
// ...
void MainWindow::addData()
{
myVec << new QVector<double>(0);
*myVec[0] << 2.7 << 3.4 << 4.5;
}
// Cleanup code you need to call when you no longer need myVec
for (auto ptr : myVec) {
delete ptr;
}
Keep in mind that you also need to delete a pointer if you remove it from myVec or override it with a different pointer. This is tedious and error prone. When you forget to do it, you leak memory. So I recommend going the unique_ptr route instead, which will automatically delete the pointer for you.
Finally, and this might be preferable in your case, you can avoid pointers altogether and move the vector into myVec by casting it to an rvalue using std::move(). Not sure how well QVector works with move semantics, but std::vector does the job just fine, in which case you'd use std::vector for both "inner" and "outer" vectors. As an optimization, if you know the amount of doubles you need to store, you can pre-allocate with reserve() to avoid costly re-allocations when you add elements:
#include <memory>
#include <vector>
std::vector<std::vector<double>> myVec;
// ...
void MainWindow::addData()
{
std::vector<double> tmpVec;
tmpVec.reserve(amount_of_elements);
tmpVec.push_back(2.4);
tmpVec.push_back(3.7);
// etc until filled
myVec.push_back(std::move(tmpVec));
}
With moving, no allocations or copies are performed, if the objects involved support move semantics. As mentioned, std::vector does.
Very important: after an object has been "moved from" (tmpVec in this case), it's in a valid but unspecified state (usually empty.)

Related

"Moving" sequential containers to pointers

I'm building a buffer for network connections where you can explicitly allocate memory or you can supply it on your own via some sequential container(eg.:std::vector,std::array)these memory chunks are stored in a list what we use later for read/write operations. (the chunks are needed for handle multiple read/write requests)
I have a question about the last part, I want to make a pointer to the container's data and then tell the container to not care about it's data anymore.
So something like move semantics.
std::vector<int> v = {9,8,7,6,5,4,3,2,1,0};
std::vector<int> _v(std::move(v));
Where _v has all the values of v and v left in a safe state.
The problem is if I just make a pointer for v.data() after the lifetime of the container ends, the data pointed by the pointer releases with the container.
For example:
// I would use span to make sure It's a sequential container
// but for simplicity i use a raw pointer
// gsl::span<int> s;
int *p;
{
std::vector<int> v = {9,8,7,6,5,4,3,2,1,0};
// s = gsl::make_span(v);
p = v.data();
}
for(int i = 0; i < 10; ++i)
std::cout << p[i] << " ";
std::cout << std::endl;
Now p contains some memory trash and i would need the memory previously owned by the vector.
I also tried v.data() = nullptr but v.data() is rvalue so it's not possible to assign it. Do you have any suggestions, or is this possible?
edit.:
To make it more clear what i'm trying to achieve:
class readbuf_type
{
struct item_type // representation of a chunk
{
uint8_t * const data;
size_t size;
inline item_type(size_t psize)
: size(psize)
, data(new uint8_t[psize])
{}
template <std::ptrdiff_t tExtent = gsl::dynamic_extent>
inline item_type(gsl::span<uint8_t,tExtent> s)
: size(s.size())
, data(s.data())
{}
inline ~item_type()
{ delete[] data; }
};
std::list<item_type> queue; // contains the memory
public:
inline size_t read(uint8_t *buffer, size_t size); // read from queue
inline size_t write(const uint8_t *buffer, size_t size); // write to queue
inline void *get_chunk(size_t size)
{
queue.emplace_back(size);
return queue.back().data;
}
template <std::ptrdiff_t tExtent = gsl::dynamic_extent>
inline void put_chunk(gsl::span<uint8_t,tExtent> arr)
{
queue.emplace_back(arr);
}
} readbuf;
I have the get_chunkfunction what basically just allocates memory with the size, and I have put_chunk what I'm struggling with, the reason i need this because before you can write to this queue you need to allocate memory and then copy all the elements from the buffer(vector,array) you're trying to write from to the queue.
Something like:
std::vector<int> v = {9,8,7,6,5,4,3,2,1,0};
// instead of this
readbuf.get_chunk(v.size);
readbuf.write(v.data(), v.size());
// we want this
readbuf.put_chunk({v});
Since we're developing for distributed systems memory is crucial and that's why we want to avoid the unnecessary allocation, copying.
ps.This is my first post, so sorry if i wasn't precise in the first place..
No, it is not possible to "steal" the buffer of the standard vector in the manner that you suggest - or any other standard container for that matter.
You've already shown one solution: Move the buffer into another vector, instead of merely taking the address (or another non-owning reference) of the buffer. Moving from the vector transfers the ownership of the internal buffer.
It would be possible to implement such custom vector class, whose buffer could be stolen, but there is a reason why vector doesn't make it possible. It can be quite difficult to prove the correctness of your program if you release resources willy-nilly. Have you considered how to prevent the data from leaking? The solution above is much simpler and easier to verify for correctness.
Another approach is to re-structure your program in such way that no references to the data of your container outlive the container itself (or any invalidating operation).
Unfortunately the memory area of the vector cannot be detached from the std::vector object. The memory area can be deleted even if you insert some data to the std::vector object. Therefore use of this memory area later is not safe, unless you are sure that this particular std::vector object exists and is not modified.
The solution to this problem is to allocate a new memory area and copy the content of the vector to this newly allocated memory area. The newly allocated memory area can be safely accessed without worrying about the state of the std::vector object.
std::vector<int> v = {1, 2, 3, 4};
int* p = new int[v.size()];
memcpy(p, v.data(), sizeof(int) * v.size());
Don't forget to delete the memory area after you are finished using this memory area.
delete [] p;
Your mistake is in thinking that the pointer "contains" memory. It doesn't contain anything, trash or ints or otherwise. It is a pointer. It points to stuff. You have deleted that stuff and not transferred it anywhere else, so it can't work any more.
In general, you will need a container to put this information in, be it another vector, or even your own hand-made array. Just having a pointer to data does not mean you have data.
Furthermore, since it is impossible to ask a vector to relinquish its buffer to a non-vector thing, a vector is really your only chance in this particular case. It's not quite clear why that's not a good enough solution for you. :)
Not sure what you try to achieve but I would use moving semantic like this:
#include <iostream>
#include <memory>
#include <vector>
int main() {
std::unique_ptr<std::vector<int>> p;
{
std::vector<int> v = {9,8,7,6,5,4,3,2,1,0};
p = std::move(make_unique<std::vector<int>>(v));
}
for(int i = 0; i < 10; ++i)
std::cout << (*p)[i] << " ";
std::cout << std::endl;
return 0;
}

How do vector elements preserve their original address after a vector std::move?

As you can see in the output, the objects of the vector pre not only "moved" to the vector post, but also preserved their original address space in memory. What is really going on behind this move? Is this behaviour expected? Say I need to have a separate vector of pointers to these objects, is it safe to assume that after this move the objects will always have their original addresses?
Actually, I have a class containing a vector like this and the vector of pointers I mentioned as members. I have also deleted the copy ctors, and defined the move ones for the class.
#include <iostream>
#include <vector>
struct B {
int val = 0;
B(int aInt) : val(aInt) { };
};
int main() {
std::vector<B> pre;
pre.push_back(B(1));
pre.push_back(B(2));
std::cout << "pre-move:\t" << (void*)&pre.at(0) << '\n';
std::cout << "pre-move:\t" << (void*)&pre.at(1) << '\n';
std::vector<B> post(std::move(pre));
std::cout << "post-move:\t" << (void*)&post.at(0) << '\n';
std::cout << "post-move:\t" << (void*)&post.at(1) << '\n';
return 0;
}
Output:
pre-move: 0x1d7b150
pre-move: 0x1d7b154 <------|
post-move: 0x1d7b150 |
post-move: 0x1d7b154 <------|
A vector is basically nothing more than a pointer to heap-allocated memory, the current length and the current capacity of the vector.
By "moving" a vector, all you're doing is copying those values, and resetting the values of the moved-from vector.
For the data of the vector, it's basically equivalent to
original_pointer = some_place_in_memory;
new_pointer = original_pointer; // Copies the *value* of original_pointer
original_pointer = nullptr;
There's no need to allocate new memory and copy the data in the vector.
The whole point of the move operation is to avoid copying the elements, so if they got copied(there is no such thing as truly "moving" the memory) the move would be just a copy.
Vectors are usually implemented as 3 pointers: begin,end and capacity. All point to a dynamically-allocated array. Then moving the vector is just copying those three pointers and so the array and elements just change their owner.
I think it should be safe to assume that pointers to the elements remain valid.
It will be clear, if we write semantically equal code without std::vector:
B* pre = new B[2]; // Declare std::vector<B> and allocate some space to make the following line correct
B[0] = 1; // pre.push_back(B(1));
B[1] = 2; // pre.push_back(B(2));
B* post = pre; // std::vector<B> post(std::move(pre));
Actually, vector move boils down to pointer copying without reallocation. Data which the pointer points at remains in it's place, so addresses of vector elements do not change.
In this code example after the fourth line, both pre and post point to the same data with same address.
std::vector is a wrapper for a pointer to array with some additional functionality. So after doing std::vector<B> post(std::move(pre));, post will contain a pointer with the same value which was in pre.

How to write a destructor for a class which includes a map<int,*double> member?

I have a class like:
class CPR_data{
public:
/*some functions*/
private:
map<int,double*> data; //saving data
};
In the file main.cpp, I add data into the class as following:
double *data_ = new double[n_var];
auto insert_flag = data.insert(make_pair(n,data_));
I used the default destructor but it seems a Memory Leak. Do I need to delete all the arrays manually in the destructor?
You loop through your map and call delete[] on every element.
~CPR_data()
{
for(auto& elem : data)
{
delete[] elem.second;
}
}
Note that you now also have to write your own copy constructor and copy assignment operator.
However, the real solution is to use std::map<int, std::vector<double>> instead so you won't have to do any bookkeeping and any questioning about who owns what pointer etc. There's a good chance it'll be as fast as your dynamic allocation method.
You really shouldn't be using any dynamic allocation in C++11 since everything nowadays has a better alternative unless you're writing a standard library implementation or some other exotic piece of code.
#include <iostream>
#include <map>
#include <vector>
using namespace std;
int main()
{
map<int, vector<double>> data;
vector<double> data_ = { 1.0, 2.0, 3.0, 4.0, 5.0 };
auto insert_flag = data.insert(make_pair(1, data_));
vector<double> data_2 = { 1.1, 2.2, 3.3, 4.4 };
insert_flag = data.insert(make_pair(2, data_2));
for(const auto& val : data[2])
cout << val << '\n';
return 0;
}
You don't need to implement your own destructor just for that case. The only thing you have to ensure is to make the double* get deleted when your object is destroyed.
Implementing a destructor that will run through all items is one option, but you can also (as others said) switch to using some other element type. vector is one option, but surely that's not an array.
If you need to stick with raw dynamic arrays, you can always wrap the raw pointer into a smart pointer that will keep track of it and will delete it appropriately.
#include <iostream>
#include <map>
#include <boost/scoped_array.hpp>
int main()
{
std::map<int,boost::scoped_array<double>> data;
int n = 250;
double* data_ = new double[n]; // POTENTIAL LEAK
data_[249] = -1; // POTENTIAL LEAK
/* ... */ // POTENTIAL LEAK
auto insert_flag = data.insert(std::make_pair(n,data_));
std::cout << insert_flag.first->first << " " << insert_flag.second << std::endl;
std::cout << data[250][249] << std::endl;
}
Please be careful with smart pointer type - here I'm using scoped_array as opposed to typical scoped_ptr which is appropriate only for pointers to single object. For dynamic arrays, scoped_array is needed.
Nevertheless, as you can see above, using smart pointer is very similar to using raw pointer. Smart pointers were designed to be as much similar in use as possible. They come with their own destructors, so when the (default) destructor of your object kicks in, it destroys the map, which in turn destroys its elements - and now the elements are smart-pointer - so they will deallocate the arrays.
Actually, I still would encourage you to use vector or whatever else than raw pointers. With raw dynamic allocations you have to be extra careful because even in my example above, there is a tiny possibility of a memory leak - if anything interrupts the code (i.e. exception) between new'ing the raw pointer and packing the pointer into scoped one - nothing will deallocate the raw dynamic array. For that reason, it's best to wrap them as soon as possible and ensure, as hard as it can be, that nothing can interrupt the flow before the raw pointer starts being managed by smart pointer object.
And, as last line - be sure to check out the difference between scoped and shared smart pointers. I used scoped here, because it seems fit. However, it's worth knowing about both types.

Delete a vector without deleting the array

I'm trying to populate a vector of doubles in C++ and pass the associated array to Fortran. But I'm having trouble freeing the rest of the memory associated with the vector. I'd like to avoid copying. Here's what I have:
std::vector<double> *vec = new std::vector<double>();
(*vec).push_back(1.0);
(*vec).push_back(2.0);
*arr = (*vec).data(); //arr goes to Fortran
How do I delete vec while keeping arr intact? Is there a way to nullify the pointer to arr in vec so that I can then delete vec?
Update
I see that I didn't give enough information here. A couple things:
I'm actually calling a C++ function in Fortran using iso_c_binding
I don't know how large the vec needs to be. The vector class looks good for this situation
I might try Guillaume's suggestion eventually, but for now, I'm passing vec to the Fortran and calling another C++ function to delete it once I'm done with the data
You need to rethink your program design.
Somehow, somewhere, you need to keep an array alive while Fortran is using it. So whatever context you're using to access Fortran should probably be responsible for ownership of this array.
class fortran_context {
/*Blah blah blah whatever API you're using to access Fortran*/
void * arr;
std::vector<double> vec; //Don't allocate this as a pointer; makes no sense!
public:
fortran_context() {
arr = //Do whatever is necessary to setup Fortran stuff. I'm assuming your
//api has some kind of "get_array_pointer" function that you'll use.
}
~fortran_context() {
//Do the cleanup for the fortran stuff
}
//If you want to spend time figuring out a robust copy constructor, you may.
//Personally, I suspect it's better to just delete it, and make this object non-copyable.
fortran_context(fortran_context const&) = delete;
std::vector<double> & get_vector() {
return vec;
}
std::vector<double> const& get_vector() const {
return vec;
}
void assign_vector_to_array() {
*arr = vec.data();
}
void do_stuff_with_fortran() {
assign_vector_to_array();
//???
}
};
int main() {
fortran_context context;
auto & vec = context.get_vector();
vec.push_back(1.0);
vec.push_back(2.0);
context.do_stuff_with_fortran();
return 0;
} //Cleanup happens automatically due to correct implementation of ~fortran_context()
I've abstracted a lot of this because I don't know what API you're using to access Fortran, and I don't know what kind of work you're doing with this array. But this is, by far, the safest way to ensure that
The vector's allocated memory exists so long as you are doing stuff in Fortran
The memory associated with the vector will be cleaned up properly when you're done.
How do I delete vec while keeping arr intact? Is there a way to nullify the pointer to arr in vec so that I can then delete vec?
The library does not provide any built-in capability to do that. You have to do the bookkeeping work yourself.
Allocate memory for the data and copy data from the vector.
Send the data to FORTRAN.
Decide when it is safe to deallocate the data and then delete them.
// Fill up data in vec
std::vector<double> vec;
vec.push_back(1.0);
vec.push_back(2.0);
// Allocate memory for arr and copy the data from vec
double* arr = new double[vec.size()];
std::copy(vec.begin(), vec.end(), arr);
// use arr
// delete arr
delete [] arr;
What you are asking for is not possible. std::vector, being a well behaved template class will release the internals that it owns and manages when it is destroyed.
You will have to keep vector alive while you are using its contents, which makes perfect sense. Otherwise, you will have to make a copy.
Also, I don't see why you are allocating the vector on the heap, it doesn't seem needed at all.
How do I delete vec while keeping arr intact? Is there a way to nullify the pointer to arr in vec so that I can then delete vec?
You don't.
I think you misuse or misunderstood what vector is for. It is not meant to expose memory management of the underlying array, but to represent a dynamically sized array as a regular type.
If you need to explicitly manage memory, I'd suggest you to use std::unique_ptr<T[]>. Since unique pointers offers a way to manage memory and to release it's resource without deleting it, I think it's a good candidate to meet your needs.
auto arr = std::make_unique<double[]>(2);
arr[0] = 1.;
arr[1] = 2.;
auto data = arr.release();
// You have to manage `data` memory manually,
// since the unique pointer released it's resource.
// arr is null here
// data is a pointer to an array, must be deleted manually later.
delete[] data;

vector of object all the same object after adding separate objects to it

So I'm adding a bunch of objects to a vector inside of my class. I am able to add everything, or it seems, just fine, but when I go to print the contents of the vector everything is the very last object that I added. Why is that? This is what it looks like when I add
this->packages.push_back(mc);
This is what it looks like when I call the object I want to print
std::cout << truck.packages[1]->getTrack() << endl;
I'm not sure what I'm doing wrong, vectors seem pretty straight forward on adding and removing items.
If I need to add anything else, please let me know.
std::cout << truck.packages[1]->getTrack() << endl;
std::cout << truck.packages[2]->getTrack() << endl;
Output: 11111
11111
This is how I create the object
if(type == 0){
Letter *letter = new Letter();
letter->setType("Letter");
letter->setWeight(weight);
letter->setTrack(track);
price = letter->cost();
letter->setPrice(price);
this->packages.push_back(letter);
truckWeight = this->getGross() + (weight / 16);
this->setGross(truckWeight);
this->numPackages++;
delete letter;
This is letter.cpp
Letter::Letter()
{
this->type = "Letter";
this->price = 0.0;
this->weight = 0;
this->trackingNumber = 0;
}
double Letter::cost()
{
int weight = this->getWeight();
if(weight > 32)
return 0.0;
else
return (0.5 * weight);
}
This is letter.h
class Letter: public Package{`enter code here`
public:
Letter();
double cost();
};
Made it with Letter. It doesn't matter which object I use. They all do the same thing
You have UB in your code. You have a vector of Letter*s. When you push_back these Letter*s, the vector just makes a copy of these pointers. Once you call delete on the original Letter*, these vector elements are now dangling. You can handle this in two ways :
Make package a vector<Letter> instead of vector<Letter*>. Now, you just happily push_back(or, preferable, emplace_back) Letters.
If you must use pointers, use unique_ptr(or some other smart pointer). So, package would be vector<unique_ptr>. When the vector gets destroyed, the unique_ptrs will take care of memory deallocation.
If you don't want to use a smart pointer, you will have to manage the deletes yourself. So, if package is a member of MyAwesomePackage(no pun intended), you would do this in the destructor:
MyAwesomePackage::~MyAwesomePackage()
{
///Other destruction
for(auto * letter : package)
delete letter;
}
While you don't show the declaration of the vector, your usage in this statement:
std::cout << truck.packages[1]->getTrack() << endl;
shows that you're not building a vector of objects, but a vector of pointers to objects.
If the vector contains only a pointer, and you modify the object referenced by this pointer after pushing the pointer into the vector, you will see the new value when you access it later through the pointer in the vector.
You are probably doing something like this:
std::vector<Package*> packages;
mc = new Package;
mc->setFoo(1);
packages.push_back(mc);
mc->setFoo(2);
packages.push_back(mc);
You now have two pointers to the same object in the vector. Since you modified the object after the first push_back() call, you will see the new value of the object when you access either element in the vector.
To make this work, you will need to either store actual objects in the vector:
std::vector<Package> packages;
or allocate a new Package object each time before you push the pointer into the vector.
After seeing the full code, your problem is a slight variation of this: You're deleting the object after pushing a pointer to it into the vector. So the vector contains pointers to objects that have been deleted, which leads to undefined behavior. What is probably happening in your test case is that when you allocate a new object after deleting the previous one, you're getting a pointer to the same memory again. That's why it looks like all values are the same. But even that is "random" and completely unspecified behavior.