如何让 class 与 std::mutex 的多个对象?
How to have multiple objects of a class with an std::mutex?
我有以下错误:
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 that one)。基于这些,我尝试了以下 class 代码:
class Filesystem {
private:
std::string dir = getCurrentPath();
mutable std::mutex fsMut;
public:
Filesystem() {}
~Filesystem() {}
Filesystem(const Filesystem&) : fsMut() { }
//Few more functions
};
...遗憾的是这不起作用(甚至更改错误)。
现在我的代码与前面提到的问题有何不同:在两个 class 中,我在 private
部分中有声明 Filesystem fs;
。然而,在我看来这完全没问题,而对于一个 class 它通过另一个 class 返回此错误(以及 class 和 Filesystem
被隐式删除)。
所以我没有复制或移动 class afaik,但是出了什么问题呢?我怎样才能改变我的代码以使其工作?
编辑:
完整错误:
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;
^~~~~~~~
和其他 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
是在 Makefile 中较早编译的,这可以解释为什么它在 class Robotsparser
.
处给出错误
你的错误意味着有一个赋值操作试图在某处发生...
在你的 Filesystem
class 中,编译器没有抱怨复制构造函数:
Filesystem(const Filesystem&) : fsMut() {} //because there is no copying of fsMut here
但是,由于您没有定义,编译器会为您生成一个复制赋值运算符。而在编译器生成的一个中,它调用每个成员的复制赋值运算符。
我认为您的意图是:您应该定义所有 Copy/Move 赋值运算符(和构造函数),并确保您不尝试 copy/move 任何实例。
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;
}
这里有完整的插图:http://coliru.stacked-crooked.com/a/75d03fd564f8b570
另外,考虑使用 lock_guard
's on both mutexes and std::lock
来锁定 copy/move 赋值运算符中的两个互斥量。
虽然我对你的意图仍有保留,但我看到了这样的成员声明:
mutable std::mutex fsMut;
mutable
的使用是从const
成员函数修改成员;这里通常是为了能够 lock/unlock 来自 const
成员函数的互斥体。
错误的第一位表示什么?
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);
它说在Htmlparser::parseLinks
,这一行
rsmap[origUrl] = Robotsparser(origUrl);
您正在使用不存在的复制赋值运算符。
它不存在的原因是编译器没有为你生成它,因为它不能,因为你的 mutex
成员class 不可复制。
但是,您真正的问题是为什么编译器首先尝试使用它:
So I am not copying or moving the class afaik
但是您可以在编译器引用的行中看到一个赋值。您没有显示 rsmap
是什么,但是查看 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
.
的 operator[]
如果您的 class 不可复制或不可分配,您将无法执行此操作 - 您需要就地构建对象。 emplace
方法执行此操作,代码类似于:
rsmap.emplace(origUrl, origUrl);
或者,您可以保留现有代码并编写 copy/move 构造函数和赋值运算符。
我有以下错误:
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;
^~~~~~~~
...关于它已经提出了一些问题(例如
class Filesystem {
private:
std::string dir = getCurrentPath();
mutable std::mutex fsMut;
public:
Filesystem() {}
~Filesystem() {}
Filesystem(const Filesystem&) : fsMut() { }
//Few more functions
};
...遗憾的是这不起作用(甚至更改错误)。
现在我的代码与前面提到的问题有何不同:在两个 class 中,我在 private
部分中有声明 Filesystem fs;
。然而,在我看来这完全没问题,而对于一个 class 它通过另一个 class 返回此错误(以及 class 和 Filesystem
被隐式删除)。
所以我没有复制或移动 class afaik,但是出了什么问题呢?我怎样才能改变我的代码以使其工作?
编辑:
完整错误:
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;
^~~~~~~~
和其他 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
是在 Makefile 中较早编译的,这可以解释为什么它在 class Robotsparser
.
你的错误意味着有一个赋值操作试图在某处发生...
在你的 Filesystem
class 中,编译器没有抱怨复制构造函数:
Filesystem(const Filesystem&) : fsMut() {} //because there is no copying of fsMut here
但是,由于您没有定义,编译器会为您生成一个复制赋值运算符。而在编译器生成的一个中,它调用每个成员的复制赋值运算符。
我认为您的意图是:您应该定义所有 Copy/Move 赋值运算符(和构造函数),并确保您不尝试 copy/move 任何实例。
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;
}
这里有完整的插图:http://coliru.stacked-crooked.com/a/75d03fd564f8b570
另外,考虑使用 lock_guard
's on both mutexes and std::lock
来锁定 copy/move 赋值运算符中的两个互斥量。
虽然我对你的意图仍有保留,但我看到了这样的成员声明:
mutable std::mutex fsMut;
mutable
的使用是从const
成员函数修改成员;这里通常是为了能够 lock/unlock 来自 const
成员函数的互斥体。
错误的第一位表示什么?
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);
它说在Htmlparser::parseLinks
,这一行
rsmap[origUrl] = Robotsparser(origUrl);
您正在使用不存在的复制赋值运算符。
它不存在的原因是编译器没有为你生成它,因为它不能,因为你的 mutex
成员class 不可复制。
但是,您真正的问题是为什么编译器首先尝试使用它:
So I am not copying or moving the class afaik
但是您可以在编译器引用的行中看到一个赋值。您没有显示 rsmap
是什么,但是查看 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
.
如果您的 class 不可复制或不可分配,您将无法执行此操作 - 您需要就地构建对象。 emplace
方法执行此操作,代码类似于:
rsmap.emplace(origUrl, origUrl);
或者,您可以保留现有代码并编写 copy/move 构造函数和赋值运算符。