I'm trying to write a class include a public thread object, and finally I want to access this thread ouside the class, but there are some errors, why?
The class defined as:
class scoped_thread {
public:
std::thread t;
explicit scoped_thread(std::thread t_) : t(std::move(t_)) {
if (!t.joinable())
throw std::logic_error("No thread");
}
~scoped_thread() {
// t.join();
}
scoped_thread(scoped_thread const &) = delete;
scoped_thread & operator = (scoped_thread const &) = delete;
};
and I'm try to access thread member:
scoped_thread th(std::thread(f));
th.t.join();
At last, the error is:
error: request for member 't' in 'th', which is of non-class type 'scoped_thread(std::thread)'
scoped_thread th(std::thread(f)); is a declaration of a function named th, returning scoped_thread and taking std::thread as a parameter. It's not a declaration of an object of type scoped_thread. Naturally, the function doesn't have members, named t or otherwise.
See also: most vexing parse.
You've run into the most vexing parse. C++ thinks you've declared a function named th instead of an object. In recent versions of C++, to correct the issue you can use curly braces instead of parentheses.
scoped_thread th{std::thread{f}}; // compiles as expected
Related
I want to know if there's a way to make the = operator trigger the constructor (or any method) of a class upon its declaration
let's say
class foo
{
public:
string variable="";
foo(string var)
{
this->variable=var;
}
foo(){}
void operator=(string var)
{
this->variable=var;
}
}
int main()
{
foo obj="new foo object";
}
When I run that, it says "error: conversion from 'const char[15]' to non-scalar type 'foo' requested"
But when I do this
foo obj;
obj="new foo object";
It works
What can I do so the first method will work?
What can I do so the first method will work?
Provide a constructor that takes an argument of type char const *.
And use the initialization list of the constructors to initialize members, not assignments in the constructors body.
BTW:
foo obj = "new foo object";
does NOT call operator=().
Why don't you just use the constructor (that should be declared as explicit anyway, so the construct you want is actually bad practice IIRC)?
Just do:
foo obj("bar");
Also variable should not have a default empty value, the default constructor will create it properly.
You should also put variable in the initializer list.
I have the following error:
filesystem.hpp:11:7: error: use of deleted function ‘std::mutex& std::mutex::operator=(const std::mutex&)’
In file included from /usr/include/c++/6.1.1/mutex:44:0,
from includes.hpp:11,
from htmlparser.hpp:4,
from htmlparser.cpp:1:
/usr/include/c++/6.1.1/bits/std_mutex.h:98:12: note: declared here
mutex& operator=(const mutex&) = delete;
^~~~~~~~
...about which there are already some questions asked (like this one and that one). Based on these I tried the following class code:
class Filesystem {
private:
std::string dir = getCurrentPath();
mutable std::mutex fsMut;
public:
Filesystem() {}
~Filesystem() {}
Filesystem(const Filesystem&) : fsMut() { }
//Few more functions
};
...which sadly enough doesn't work (or even change the errors).
Now how does my code differ from the previously mentioned questions: In two classes I have in the private section the declaration Filesystem fs;. Which in my opinion would be totally fine, however, while for one class it passes for the other class this error is returned (along with the errors how that class and Filesystem are deleted implicitly).
So I am not copying or moving the class afaik, but what does go wrong then? And how can I alter my code to make it work?
EDIT:
Full error:
htmlparser.cpp: In member function ‘strSet Htmlparser::parseLinks(std::__cxx11::string, std::__cxx11::string, std::__cxx11::string)’:
htmlparser.cpp:10:39: error: use of deleted function ‘Robotsparser& Robotsparser::operator=(const Robotsparser&)’
rsmap[origUrl] = Robotsparser(origUrl);
^
In file included from htmlparser.hpp:5:0,
from htmlparser.cpp:1:
robotsparser.hpp:7:7: note: ‘Robotsparser& Robotsparser::operator=(const Robotsparser&)’ is implicitly deleted because the default definition would be ill-formed:
class Robotsparser {
^~~~~~~~~~~~
robotsparser.hpp:7:7: error: use of deleted function ‘Filesystem& Filesystem::operator=(const Filesystem&)’
In file included from robotsparser.hpp:5:0,
from htmlparser.hpp:5,
from htmlparser.cpp:1:
filesystem.hpp:11:7: note: ‘Filesystem& Filesystem::operator=(const Filesystem&)’ is implicitly deleted because the default definition would be ill-formed:
class Filesystem {
^~~~~~~~~~
filesystem.hpp:11:7: error: use of deleted function ‘std::mutex& std::mutex::operator=(const std::mutex&)’
In file included from /usr/include/c++/6.1.1/mutex:44:0,
from includes.hpp:11,
from htmlparser.hpp:4,
from htmlparser.cpp:1:
/usr/include/c++/6.1.1/bits/std_mutex.h:98:12: note: declared here
mutex& operator=(const mutex&) = delete;
^~~~~~~~
And the other classes:
class Robotsparser {
private:
std::string url;
Filesystem fs;
public:
Robotsparser(std::string u) : url(u) {}
~Robotsparser() {}
};
class A {
private:
std::mutex crawlMut;
Filesystem fs;
public:
A(std::string);
};
Class A is compiled earlier in the Makefile, which might explain why it gives the error at class Robotsparser.
Your error means that there is an assignment operation trying to happen somewhere...
In your Filesystem class, the compiler didn't complain of the copy constructor:
Filesystem(const Filesystem&) : fsMut() {} //because there is no copying of fsMut here
But, the compiler generates a copy assignment operator for you since you didn't define one. And in the compiler generated one, it calls the copy assignment operator of each member.
For what I think your intent are: You should define all your Copy/Move Assignment operators (and Constructors), and make sure you do not try to copy/move the mutex owned by any of the instances.
Filesystem(const Filesystem& f2)
{
std::lock_guard<std::mutex> lk2(f2.fsMut);
/*do your stuff but do not copy f2.fsMut*/
}
Filesystem(Filesystem&& f2)
{
std::lock_guard<std::mutex> lk2(f2.fsMut);
/*do your stuff but do not move f2.fsMut*/
}
Filesystem& operator = (const Filesystem&)
{
std::lock(this->fsMut, f2.fsMut);
std::lock_guard<std::mutex> lk1(this->fsMut, std::adopt_lock);
std::lock_guard<std::mutex> lk2(f2.fsMut, std::adopt_lock);
//do your stuff but do not copy fsMut
return *this;
}
Filesystem& operator = (Filesystem&& f2)
{
std::lock(this->fsMut, f2.fsMut);
std::lock_guard<std::mutex> lk1(this->fsMut, std::adopt_lock);
std::lock_guard<std::mutex> lk2(f2.fsMut, std::adopt_lock);
//do your stuff but do not move fsMut
return *this;
}
Full illustration here: http://coliru.stacked-crooked.com/a/75d03fd564f8b570
Also, consider using, lock_guard's on both mutexes and std::lock to lock both mutexes in the copy/move assignment operators.
Though I still have my reservations on your intent, I saw a member declaration like:
mutable std::mutex fsMut;
The use of mutable is to modify members from a const member function; here its typically for being able to lock/unlock the mutex from a const member function.
What does the first bit of the error say?
htmlparser.cpp: In member function ‘strSet Htmlparser::parseLinks(std::__cxx11::string, std::__cxx11::string, std::__cxx11::string)’:
htmlparser.cpp:10:39: error: use of deleted function ‘Robotsparser& Robotsparser::operator=(const Robotsparser&)’
rsmap[origUrl] = Robotsparser(origUrl);
It says that in Htmlparser::parseLinks, on this line
rsmap[origUrl] = Robotsparser(origUrl);
you're using a copy assignment operator that doesn't exist.
The reason it doesn't exist is that the compiler didn't generate it for you, because it can't, because the mutex member of your class isn't copyable.
However, your real question is why the compiler is trying to use this in the first place:
So I am not copying or moving the class afaik
but you can see, on the line the compiler quoted, an assignment. You haven't shown what rsmap is, but looking at operator[] for std::map shows that it default constructs an element, returns a reference to the new value, and then your code copy-assigns to it. The same is true for std::unordered_map.
If your class isn't copyable or assignable, you can't do this - you need to construct the object in place. The emplace method does this, giving code something like:
rsmap.emplace(origUrl, origUrl);
Alternatively, you can keep your existing code and write the copy/move constructors and assignment operators.
class A
{
private:
A () {}
public:
static A* getInstance ()
{
return new A ();
}
};
int main ()
{
A.getInstance ();
return 0;
}
results in the error stated in the title. I do realize that if I create a variable in class A and instanciate it there and return it directly, the error will vanish.
But, here I want to understand what is the meaning of this error and why can't I use it this way.
You need to call the method using the scope resolution operator - :::
A::getInstance ();
Also, if this is meant to be a singleton, it's a very bad one. Whenever you call getInstance(), you'll receive a new object, and you'll run into memory leaks if you forget to delete any instances.
A singleton is usually implemented like so:
class A
{
private:
A () {}
static A* instance;
public:
static A* getInstance ()
{
if ( !instance )
instance = new A ();
return instance;
}
};
//implementation file
A* A::instance = NULL;
Use scope resolution operator :: (not . like in Java for example):
A::getInstance();
getInstance is a static function of class A. The right form of calling a static function of a class is <class_name>::<static_function_name>.
We can also call the static function by creating object of the class and using . operator:
<class_object>.<static_function_name>
You can call a static member function using either . or ::. However, if you use class name you need to use the latter and an object then use the former.
use scope Resolution Operator ::
e.g.
class::methodName()
Here is the example of the "scoped lock" idiom with common mistake: no local variable is created, so lock is not in effect. This code compiles flawlessly both with VC++ 2010 and Comeau C++ online:
class Mutex
{
public:
void lock() {}
};
class ScopedLock
{
public:
ScopedLock() : m_pm(0) {}
ScopedLock(Mutex& m) : m_pm(&m) { m_pm->lock(); }
private:
Mutex* m_pm;
private:
ScopedLock& operator =(const ScopedLock&);
ScopedLock(const ScopedLock&);
};
class X
{
public:
void foo() const
{
ScopedLock(m_mutex);
}
private:
Mutex m_mutex;
};
int main()
{
X x1;
x1.foo();
}
If default constructor for ScopedLock is commented out, then both compilers give an error:
error C2512: 'ScopedLock' : no appropriate default constructor available
(When ScopedLock used correctly, i.e. local variable is created: ScopedLock guard(m_mutex);, then compilation fails as expected. Declaring m_mutex as mutable fixes the problem.)
I have two questions:
Why X::foo compiles? It seems that compiler was able to cast const Mutex& to Mutex& somehow.
What role plays ScopedLock default constructor, so the compilation succeeds?
Thanks.
Update: I found the answer. It appears that ScopedLock(m_mutex); statement creates a local variable m_mutex of type ScopedLock. Not a temporary. That's why ScopedLock::ScopedLock default constructor is required.
You answered the question yourself.
It appears that ScopedLock(m_mutex); statement creates a local variable m_mutex of type ScopedLock
The explanation is to be found in the Standard's Section 6.8 Ambiguity Resolution:
There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion [5.2.3] as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration.
The Standard then lists T(a); as an example of a statement that is really a declaration. It is equivalent to T a;
This is one variation of the infamous C++ "most vexing parse".
I'm pretty sure your problem is line 26: ScopedLock(m_mutex);
Instead, that should be something like ScopedLock a_variable_name(m_mutex);
When I make that change, I get the expected errors:
constCorrectness.cpp: In member function ‘void X::foo() const’:
constCorrectness.cpp:26: error: no matching function for call to ‘ScopedLock::ScopedLock(const Mutex&)’
constCorrectness.cpp:18: note: candidates are: ScopedLock::ScopedLock(const ScopedLock&)
constCorrectness.cpp:11: note: ScopedLock::ScopedLock(Mutex&)
constCorrectness.cpp:10: note: ScopedLock::ScopedLock()
Perhaps somebody can interpret ScopedLock(m_mutex) for us? Does it declare a function or something? Instead of calling a constructor as expected by the questioner? Update: Striking this out. I think it's just a variable declaration (i.e. the brackets are ignored.)
The problem is that the X::foo() method is declared as const - that means that it will not mutate (change) the object.
The ScopedLock() constructor doesn't have a overload that accepts a immutable (const) reference to a Mutex object.
Fixing this requires you declare m_mutex as mutable, or provide an appropriate overloaded ScopedLock() constructor. I'm thinking the former is preferable.
I got into a problem with my classes, passing a const object (polymorphic structure) to an explicit constructor which takes a const reference to the base class of that polymorphic structure.
Here is the sample (this is not from my code, it is for explanation here)
class Base
{
...
}
class Derived:public Base
{
...
}
class Problem
{
Problem(const Base&);
...
}
void myFunction(const Problem& problem)
{
...
}
int main()
{
//explicit constructor with non const object
Derived d;
Problem no1(d); //this is working fine
myFunction(no1);
//implicit constructor with const object
Problem no2=Derived(); //this is working fine, debugged and everything called fine
myFunction(no2); //is working fine
//explicit constructor with const object NOT WORKING
Problem no3(Derived()); //debugger jumps over this line (no compiler error here)
myFunction(no3); //this line is NOT COMPILING at all it says that:
//no matching function for call to myFunction(Problem (&)(Derived))
//note: candidates are: void MyFunction(const Problem&)
}
It seems that it is working fine with the second version (explicit constructor call for Problem) only if i explicitly cast the Derived object to its base class Base it like:
Problem(*(Base*)&Derived);
I do not realize the difference between calling impicitly and explicitly the constructor of the Problem class.
Thank you!
The problem is you aren't declaring an object, but a function:
Problem no3(Derived());
// equivalent to:
Problem no3(Derived); // with parameter name omitted
Use:
Problem no3((Derived()));
// extra parens prevent function-declaration interpretation
// which is otherwise required by the standard (so that the code isn't ambiguous)
This is a quirk of C's declaration syntax inherited by C++.
More examples:
void f(int(a)); /* same as: */ void f(int a);
void g() {
void function(int); // declare function
void function(int()); // we can declare it again
void function(int=42); // add default value
function(); // calls ::function(42) ('function' in the global scope)
}
// 'function' not available here (not declared)
void function(int) {} // definition for declarations inside g above
For future reference, this is a quirk known as the most vexing parse, see another StackOverflow thread as to the origin of this nickname.