代码之家  ›  专栏  ›  技术社区  ›  Olympionex

使用Auto时,使用虚拟析构函数强制复制派生类中的构造函数

  •  0
  • Olympionex  · 技术社区  · 7 年前

    我试图派生std::unique\u lock,但遇到了一个无法用更简单的类复制的问题。下面是复制问题的可编译代码:

    #include <iostream>
    #include <mutex>
    #include <string>
    
    template<class T>
    class A : public std::unique_lock<T>
    {
     public:
      template<typename... Args>
      A(const std::string name, Args&&... args) : name_(name), 
      std::unique_lock<T>(args...) { }
      virtual ~A() {}  // if this destructor exists...
      private:
      std::string name_;
    };
    
    
    int main()
    {
      std::timed_mutex tm;
      auto a = A<std::timed_mutex>("Hello", tm, std::defer_lock); // this line fails
      A<std::timed_mutex> a("Hello", tm, std::defer_lock); // this line works
      return 0;
    }
    

    如果存在虚拟析构函数(我实际的类需要该析构函数),那么我就不能使用带有auto的行来实例化该类,因为最终调用std::unique\u lock中的析构函数是删除的,它采用常量;已删除的互斥体(b/c lock类无法处理常量互斥体)。我假设它调用了deleted const ctor,因为出于某种原因,它调用了A()中的copy构造函数,该构造函数以一个const&作为输入;A(根据下面的错误日志)。如果我只使用非自动样式的实例化代码(带标签),那么它可以很好地编译。

    我将gcc 5.4.1与 设置(CMAKE\U CXX\U STANDARD 11)设置。我也试过14和17,所以我假设我使用的不是cpp。

    1 回复  |  直到 7 年前
        1
  •  1
  •   Miles Budnek    7 年前

    如果类包含用户声明的析构函数、复制构造函数或赋值运算符,则编译器不会隐式生成移动构造函数。自从 A 没有移动构造函数,编译器会返回到复制构造函数,该构造函数会被隐式删除,因为 std::unique_lock 的复制构造函数已删除。

    您可以显式声明移动构造函数以使事情正常工作:

    template<class T>
    class A : public std::unique_lock<T>
    {
    public:
      template<typename... Args>
      A(const std::string name, Args&&... args)
        : std::unique_lock<T>(args...),
          name_(name)
      { }
      A(A&&) = default;
      virtual ~A() {}
    private:
      std::string name_;
    };
    

    Live example

    您可能还应该声明一个移动赋值操作符,但在这种情况下不需要这样做。