Attempting to reference a deleted function, structure with mutex member - c++

Here's my problem.
I have a structure like this.
struct threadInfo
{
std::condition_variable cv;
std::mutex m;
int priorityLevel;
};
When building my code I get this error
Error C2280 threadInfo::threadInfo(const threadInfo &): attempting
to reference a deleted function PriorityListMutex
From my understanding it means that the constructor for threadInfo is called and it tries to copy the mutex which is not possible.
I don't have much experience with c++ and even though I somewhat understand what is happening, I'm not sure how to attempt to fix this. Any help would be great!
Here is the code that uses ThreadInfo
threadInfo info;
info.priorityLevel = priority;
priorityListMutex.lock();
for (std::list<threadInfo>::iterator it = threadList.begin(); it != threadList.end(); it++)
{
if ((*it).priorityLevel < info.priorityLevel)
{
threadList.insert(it, info);
break;
}
else if (it == threadList.end())
{
threadList.push_back(info);
break;
}
}
priorityListMutex.unlock();
std::unique_lock<std::mutex> lock(info.m);
info.cv.wait(lock);
I guess the structure is being copied somewhere in there, but I'm completely missing where.

You can solve your problem by avoiding copies and emplacing the structs directly in the list. This does require a custom constructor though. I've shortened your code sample to only show the emplacing portion:
#include <mutex>
#include <condition_variable>
#include <list>
struct threadInfo
{
explicit threadInfo(int prio) : priorityLevel(prio) {}
std::condition_variable cv;
std::mutex m;
int priorityLevel;
};
int main()
{
std::list<threadInfo> threadList;
int priorityLevel = 0;
for (std::list<threadInfo>::iterator it = threadList.begin(); it != threadList.end(); it++)
{
if ((*it).priorityLevel < priorityLevel)
{
threadList.emplace(it, priorityLevel);
break;
}
else if (it == threadList.end())
{
threadList.emplace_back(priorityLevel);
break;
}
}
return 0;
}

In the Standard C++ Library, classes related to threading, like mutex, do not have a copy constructor.
When an assignment involves two objects, like
Class b(10);
Class a = b;
At the second line, we try to create an object initializing from another object. This makes the compiler look for a copy constructor, a constructor developed specifically for this purpose.
Since having two identical copy of a mutex is not good, the library doesn't use such method for thread related classes.
Usually compilers create default copy-constructors in case they are needed, but when a class a property of this type it cannot do so, so it gives you and error.
To solve, you will have to explicitly define a copy constructor and handle manually. Beware, you should keep in mind that things related to threads like mutex and cv should not exists in more than one copy.

The copy constructor of mutex is deleted explicitly. You can't copy a mutex, however, if what you are doing is moving rather than copying (e.g. you won't need the old value of you threadInfo object) than you can move the mutex using std::move and writing a move constructor for your threadInfo object.
However, a move constructor can cause hard to spot bug so I wouldn't recommend that. A more straight forward way would be to wrap your "info" object in a pointer and use that. You can achieve that as such:
auto info = std::make_shared<threadInfo>{};
info->priorityLevel = priority;
priorityListMutex.lock();
for (std::list<std::shared_ptr<threadInfo>>::iterator it = threadList.begin(); it != threadList.end(); it++)
{
if ((*it).priorityLevel < info->priorityLevel)
{
threadList.insert(it, info);
break;
}
else if (it == threadList.end())
{
threadList.push_back(info);
break;
}
}
priorityListMutex.unlock();
std::unique_lock<std::mutex> lock(info.m);
info->cv.wait(lock);
Do note however, that in this case I'm using a shared_ptr, which is the "easiest" way to do this since it won't break anything but probably not want you want to do, what you most likely want to do, is give the 'threadList' object ownership of your info object. in which case you would declare it as a unique_ptr:
auto info = std::make_uniq<threadInfo>{};
and move it into the threadList:
threadList.insert(it, std::move(info));

Related

Storing objects in an std::map

I'd like to store objects of a class in an std::map. Here is a working example showing how I am doing it currenty
#include <iostream>
#include <map>
class A
{
private:
int a;
std::string b;
public:
A(int init_a, std::string init_b) : a(init_a), b(init_b){};
void output_a() {std::cout << a << "\n";}
};
int main()
{
std::map<size_t, A> result_map;
for (size_t iter = 0; iter < 10; ++iter)
{
A a(iter, "bb");
result_map.insert(std::make_pair(iter, a));
}
return 0;
}
I have two question to this example:
Is this the professional C++-way to store objects in an std::map in the above case? Or should I create a pointer to an object of A and store that instead? I like the first (current) option as I don't have to worry about memory management myself by using new and delete - but most importantly I'd like to do things properly.
How would I go about calling a member function of, say, result_map[0]? I naively tried result_map[0].output_a(), but that gave me the error: error: no matching function for call to ‘A::A()’
Is this the professional C++-way to store objects in an std::map in the above case?
It is fine, simpler code could be:
result_map.emplace(iter, A(iter, "bb") );
you should use whatever you find more readable. By the way calling integer counter iter is not a way to write a readable code.
How would I go about calling a member function of, say, result_map[0]?
You better use std::map::find:
auto f = result_map.find( 0 );
if( f != result_map.end() ) f->output_a();
problem with operator[] in your case - it has to create and instance if object does not exist with that index but you do not have default ctor for A.
1- It depends: If your class can be copied and you're not worried about performance issues with copying objects into the map, then that's a good way to do it. However, if say your class held any immutable data (std::mutex for example) you'd have to use a pointer, as the copy constructor c++ automatically generates would be ill formed, so it merely wouldn't be able to copy the class
2- result_map.at(0).output_a() or result_map.at(0)->output_a() if you're using a map of pointers

C++ How to avoid access of members, of a object that was not yet initialized

What are good practice options for passing around objects in a program, avoiding accessing non initialized member variables.
I wrote a small example which I think explains the problem very well.
#include <vector>
using namespace std;
class container{public:container(){}
vector<int> LongList;
bool otherInfo;
};
class Ship
{
public:Ship(){}
container* pContainer;
};
int main()
{
//Create contianer on ship1
Ship ship1;
ship1.pContainer = new container;
ship1.pContainer->LongList.push_back(33);
ship1.pContainer->otherInfo = true;
Ship ship2;
//Transfer container from ship1 onto ship2
ship2.pContainer = ship1.pContainer;
ship1.pContainer = 0;
//2000 lines of code further...
//embedded in 100 if statements....
bool info = ship1.pContainer->otherInfo;
//and the program crashes
return 0;
}
The compiler cannot determine if you are introducing undefined behavior like shown in your example. So there's no way to determine if the pointer variable was initialized or not, other than initializing it with a "special value".
What are good practice options for passing around objects in a program, avoiding accessing non initialized member variables.
The best practice is always to initialize the pointer, and check before dereferencing it:
class Ship {
public:
Ship() : pContainer(nullptr) {}
// ^^^^^^^^^^^^^^^^^^^^^
container* pContainer;
};
// ...
if(ship1.pContainer->LongList) {
ship1.pContainer->LongList.push_back(33);
}
As for your comment:
So there are no compiler flags that could warn me?
There are more simple and obvious cases, where the compiler may leave you with a warning:
int i;
std::cout << i << std::endl;
Spits out
main.cpp: In functin 'int main()':
main.cpp:5:18: warning: 'i' is used uninitialized in this function [-Wuninitialized]
std::cout << i << std::endl;
^
See Live Demo
One good practice to enforce the checks is to use std::optional or boost::optional.
class Ship
{
public:
Ship() : pContainer(nullptr) {}
std::optional<container*> Container()
{
if(!pContainer)
return {};
return pContainer;
}
private:
container* pContainer;
};
It will force you (or better: provide a firm reminder) to check the result of your getter:
std::optional<container*> container = ship1.Container();
container->otherInfo; // will not compile
if(container)
(*container)->otherInfo; // will compile
You would always need to check the result of operation if you use pointers. What I mean is that with optional the situation is more explicit and there's less probability that you as the programmer will forget to check the result.
It seems that you are looking for a way to make your code
bool info = ship1.pContainer->otherInfo;
work even though the pContainer may be null.
You can use a sentinel object, which holds some default data:
container default_container;
default_container.otherInfo = false; // or whatever the default is
Then use a pointer to the sentinel object instead of a null pointer:
//Transfer container from ship1 onto ship2
ship2.pContainer = ship1.pContainer;
ship1.pContainer = &default_container; // instead of 0
//2000 lines of code further...
//embedded in 100 if statements....
bool info = ship1.pContainer->otherInfo;
If you use this, you should make sure the sentinel object cannot be destroyed (e.g. make it a static member, or a singleton).
Also, in the constructor, initialize your pointers so they point to the sentinel object:
class Ship
{
public: Ship(): pContainer(&default_container) {}
...
};
I found an additional solution. It is admittedly not preventing the access of uninitialized objects, but at least the program crashes AND returns an error message, that enables us to correct our mistake. (This solution is particularly for the g++ compiler.)
First of all set the compiler flag _GLIBCXX_DEBUG. Then instead of naked pointer use unique_ptr.
#include <vector>
#include <iostream>
#include <memory>
using namespace std;
class container{
public:container(){}
int otherInfo = 33;
};
class Ship
{
public:Ship(){}
std::unique_ptr<container> upContainer;
};
int main()
{
Ship ship1;
cout<<ship1.upContainer->otherInfo<<endl;
return 0;
}
This code will produce an error:
std::unique_ptr<_Tp, _Dp>::pointer = container*]: Assertion 'get() != pointer()' failed.
Hence telling us that we should probably include an if(ship1.upContainer) check.
What are good practice options for passing around objects in a program, avoiding accessing non initialized member variables.
Good practice would be to initialize everything in the constructor.
Debatable better practice is to initialize everything in the constructor and provide no way of modifying any members.

Access variable outside try-catch block

I have the following code:
class ClassA
{
public:
ClassA(std::string str);
std::string GetSomething();
};
int main()
{
std::string s = "";
try
{
ClassA a = ClassA(s);
}
catch(...)
{
//Do something
exit(1);
}
std::string result = a.GetSomething();
//Some large amount of code using 'a' out there.
}
I would like the last line could access the a variable. How could I achieve that, given ClassA doesn't have default constructor ClassA() and I would not like to use pointers? Is the only way to add a default constructor to ClassA?
You can't or shouldn't. Instead you could just use it within the try block, something like:
try
{
ClassA a = ClassA(s);
std::string result = a.GetSomething();
}
catch(...)
{
//Do something
exit(1);
}
The reason is that since a goes out of scope after the try block referring to the object after that is undefined behavior (if you have a pointer to where it were).
If you're concerned with a.GetSomething or the assignment throws you could put a try-catch around that:
try
{
ClassA a = ClassA(s);
try {
std::string result = a.GetSomething();
}
catch(...) {
// handle exceptions not from the constructor
}
}
catch(...)
{
//Do something only for exception from the constructor
exit(1);
}
You can use some sort of optional or just use std::unique_ptr.
int main()
{
std::string s = "";
std::unique_ptr<ClassA> pa;
try
{
pa.reset(new ClassA(s));
}
catch
{
//Do something
exit(1);
}
ClassA& a = *pa; // safe because of the exit(1) in catch() block
std::string result = a.GetSomething();
//Some large amount of code using 'a' out there.
}
Of course, just extending the try block to include the usage of a is the simplest solution.
Also, if you were really planning to exit(1) or otherwise abort the program on failure then simply don't put a try block here at all. The exception will propagate up, aborting the program if it is not caught .
One alternative is to use std::optional . This is the same sort of concept as using a pointer, but it uses automatic allocation and so you are less likely to create a memory leak. This is currently experimental status; you can use boost::optional instead if your compiler doesn't have std::experimental::optional:
#include <experimental/optional>
using std::experimental::optional;
using std::experimental::in_place;
// ...
optional<ClassA> a;
try
{
a = optional<ClassA>(in_place, s);
}
catch(...)
{
// display message or something
}
std::string result;
if ( a )
result = a->GetSomething();
I'd like to reiterate though that this is a bit of a spaghetti style and it'd be better to design your code differently so you aren't continually testing whether construction succeeded or failed.
This requires ClassA be movable or copyable. The in_place is a special argument which invokes a perfect forwarding constructor for the remaining arguments. Without in_place you can only give an actual ClassA as constructor argument, it doesn't consider implicit conversions to ClassA. (This is how optional avoids the ambiguity between copy-construction and list-initialization from object of the same type).

Copy constructor related compiler error

I have a resource that is shared between two concurrent threads. The resource contains a vector that both threads need to read and write to. Hence, I make access to the vector exclusive through a mutex. So far so good, sharing of resource works well without any problems.
However, the problem starts when I try to write a copy constructor for sharedResource as follows.
class sharedResource{
public:
sharedResource(){}
sharedResource(const sharedResource &other) {
vec = other.GetVec();
}
std::vector<int> GetVec() const {
std::lock_guard<std::mutex> lock(vecMutex); // Gives error
return vec;
}
private:
std::vector<int> vec;
std::mutex vecMutex;
};
int main()
{
sharedResource bacon1;
sharedResource bacon2 = bacon1;
return 0;
}
For this code, I get error
error C2664: 'std::lock_guard<std::mutex>::lock_guard(const std::lock_guard<std::mutex> &)' : cannot convert argument 1 from 'const std::mutex' to 'std::mutex &'
Could you please explain why am I getting the error and if there is a way to use the mutex without getting the compiler error.
If all else fails, I am going to create a thread unsafe GetVec2 member function, that will return vec without going through lock guard. But I would like to avoid this eventuality.
std::vector<int> GetVec2() const {
return vec;
}
This happens because getVec() is a const method but vecMutex is not mutable. You should either make getVec() non-const so it can modify (acquire) the mutex, or make the mutex mutable so it can be acquired by const methods too. I'd probably do the latter.
The quick answer is to make the vecMutex mutable.
mutable std::mutex vecMutex;
There is another non-standard issue with your code. Your default and copy constructor are declared incorrectly. It should be this:
sharedResource(){}
sharedResource(const sharedResource &other)
{
vec = other.GetVec();
}
You're also missing assignment operator.

Is a default value of nullptr in a map of pointers defined behaviour?

The following code seems to always follow the true branch.
#include <map>
#include <iostream>
class TestClass {
// implementation
}
int main() {
std::map<int, TestClass*> TestMap;
if (TestMap[203] == nullptr) {
std::cout << "true";
} else {
std::cout << "false";
}
return 0;
}
Is it defined behaviour for an uninitialized pointer to point at nullptr, or an artifact of my compiler?
If not, how can I ensure portability of the following code? Currently, I'm using similar logic to return the correct singleton instance for a log file:
#include <string>
#include <map>
class Log {
public:
static Log* get_instance(std::string path);
protected:
Log(std::string path) : path(path), log(path) {};
std::string path;
std::ostream log;
private:
static std::map<std::string, Log*> instances;
};
std::map<std::string, Log*> Log::instances = std::map<std::string, Log*>();
Log* Log::get_instance(std::string path) {
if (instances[path] == nullptr) {
instances[path] = new Log(path);
}
return instances[path];
}
One solution would be to use something similar to this where you use a special function provide a default value when checking a map. However, my understanding is that this would cause the complexity of the lookup to be O(n) instead of O(1). This isn't too much of an issue in my scenario (there would only ever be a handful of logs), but a better solution would be somehow to force pointers of type Log* to reference nullptr by default thus making the lookup check O(1) and portable at the same time. Is this possible and if so, how would I do it?
The map always value-initializes its members (in situations where they are not copy-initialized, of course), and value-initialization for builtin types means zero-initialization, therefore it is indeed defined behaviour. This is especially true for the value part of new keys generated when accessing elements with operator[] which didn't exist before calling that.
Note however that an uninizialized pointer is not necessarily a null pointer; indeed, just reading its value already invokes undefined behaviour (and might case a segmentation fault on certain platforms under certain circumstances). The point is that pointers in maps are not uninitialized. So if you write for example
void foo()
{
TestClass* p;
// ...
}
p will not be initialized to nullptr.
Note however that you might want to check for presence instead, to avoid accumulating unnecessary entries. You'd check for presence using the find member function:
map<int, TestClass*>::iterator it = TestMap.find(203);
if (it == map.end())
{
// there's no such element in the map
}
else
{
TestClass* p = it->second;
// ...
}
Yes, that's defined behaviour. If an element isn't yet in a map when you access it via operator[], it gets default constructed.