0

I am still collecting my experience with C++ and I am currently biting my teeth with instanciating classes into a vector if the class contains a vector. Enviroment: Visual Studio 2019, so using latest (C++17).

Situation: I need to implement a data-holding class which:

-stores a data-tupel,

-need to store multiple instances of this class all containing different data (using a vector probably best),

-and read- and write-access needs to be thread-safe per data-instance.

Background is that one thread updates the data from another source and the second thread further modifies the data and generates output from it.

Schematic example code (the original code is still too messy):

// mutex_testing.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include <iostream>
#include <mutex>
#include <vector>
using namespace std;

class Data {
public:
    mutex update_block{};
    void write_data(int data) {
        unique_lock<mutex> lock{ update_block };
        x = data;
    }
    int read_data() {
        unique_lock<mutex> lock{ update_block };
        return(x);
    }

    Data(int in) : x{ in } {};

private:
    int x{ 0 };
};

int main() {
    vector<Data> datastore{};
    datastore.push_back(*new Data{ 1 });
    datastore.push_back(*new Data{ 2 });
    Data demo{ *new Data{3} };
    datastore.emplace_back(4);
};

The class works fine without a mutex. However, as soon as I try to instanciate it with *new, it tries to copy the instance, which of course hits the deleted copy operator of mutex Same problem. How can I get something into the vector without somehow triggering a copy? I thought emplace_back was supposed to do only move?

//EDIT: I have worked through Stroustrups "Programming: principles and practice using C++" and are using also his main C++ reference Edition 4, if somebody wants to point me there, but all the threading examples and references are only using global mutex's, and from my understanding out of the reference my forced moves should work?!

//EDIT2: thanks for the first advices, regarding the pointer use, I will have to read again into unique_pointer referenced in How can I use something like std::vector<std::mutex>? . I will also try to post a reproducable example.

//EDIT3: now "running" code (except the mentioned problem), sorry for this. Regarding ressource allocation with the new: that was actually a question I had. I believed when I do:

datastore.push_back(*new Data{ 1 });

as soon as datastore goes out of scope, the destructor of vector is called, which shoud call the destructor of data, which should free the space allocated to x as I did not 'new' it in the class definition. Do I mess this up with my pushback-new?

Sacharon
  • 1
  • 2
  • 2
    not the immediate problem, but you shouldnt be using `new` here and certainly not `*new Data{1}`. Read [Why should C++ programmers minimize the use of new?](https://stackoverflow.com/questions/6500313/why-should-c-programmers-minimize-use-of-new) – 463035818_is_not_a_number Apr 07 '20 at 11:45
  • 1
    a mutex can neither be copied or moved. You could have a pointer to the mutex (for details see the duplicate). – 463035818_is_not_a_number Apr 07 '20 at 11:51
  • 1
    Your code have several errors, amongst them memory leak, "*new Data{1}", My guess is that you have learned Java in an earlier life which haunts you now. Try using a std::dequeue if you don't want to change to std::vector. – Surt Apr 07 '20 at 12:00
  • I have edited it to clarify code and @Surt trying to understand what you mean regarding memory leak? – Sacharon Apr 07 '20 at 12:46
  • @Sacharon, I'm 99% sure your a java programmer :) "datastore.push_back(*new Data{ 1 });" makes a copy of the newly allocated Data and then doesn't keep the information of the pointer around and as there is no garbage collection the memory is leaked. Instead you should use "datastore.push_back(1);" which constructs a Data in the vector with the arguments forwarded to the constructor. Hope this is more clear. – Surt Apr 11 '20 at 15:00

0 Answers0