如何使一个类的多个对象具有std::互斥

How to have multiple objects of a class with an std::mutex?

本文关键字:std 互斥 何使一 对象      更新时间:2023-10-16

我有以下错误:

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
};

遗憾的是,这并不奏效(甚至无法改变错误)。

现在,我的代码与前面提到的问题有何不同:在private部分的两个类中,声明Filesystem fs;。然而,在我看来,这是完全可以的,而对于一个类,它传递给另一个类时,会返回此错误(以及如何隐式删除该类和Filesystem的错误)
所以我不是在复制或移动类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;
            ^~~~~~~~

其他类别:

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);
};

A是在Makefile的早期编译的,这可能解释了它在类Robotsparser中给出错误的原因。

您的错误意味着有一个赋值操作试图在某个地方发生。。。

Filesystem类中,编译器没有抱怨复制构造函数:

 Filesystem(const Filesystem&) : fsMut() {} //because there is no copying of fsMut here

但是,编译器会为您生成一个复制赋值运算符,因为您没有定义一个。在编译器生成的一个中,它调用每个成员的复制赋值运算符。

我认为你的意图是:你应该定义所有的复制/移动赋值操作符(和构造函数),并确保你不会试图复制/移动任何实例所拥有的互斥体。

 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,在复制/移动分配运算符中使用std::lock来锁定两个互斥。

尽管我对你的意图仍持保留意见,但我看到了一份会员声明,内容如下:

mutable std::mutex fsMut;

mutable的使用是从const成员函数中修改成员;这里通常是为了能够从CCD_ 11成员函数锁定/解锁互斥。

错误的第一位表示什么?

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成员不可复制。

然而,您真正的问题是,为什么编译器首先尝试使用这个:

所以我没有复制或移动类afaik

但你可以在编译器引用的那一行看到一个赋值。您还没有显示rsmap是什么,但查看std::map的运算符[]可以发现,它默认构造一个元素,返回对新值的引用,然后您的代码副本分配给它。std::unordered_map也是如此。

如果你的类不可复制或不可赋值,你就不能这样做——你需要在适当的位置构造对象。emplace方法实现了这一点,给出了类似于的代码

rsmap.emplace(origUrl, origUrl);

或者,您可以保留现有代码并编写复制/移动构造函数和赋值运算符。