【问题标题】:Forced copy constructor in derived class with virtual destructor when using Auto使用 Auto 时在派生类中使用虚拟析构函数强制复制构造函数
【发布时间】:2018-08-26 06:00:54
【问题描述】:

我试图派生 std::unique_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_lock 中的 ctor 是已删除的需要 const T&被删除的互斥锁(b/c 锁类不能处理 const 互斥锁)。我假设它调用了删除的 const ctor,因为由于某种原因,它调用了 A() 中的复制构造函数,该构造函数将 const &A 作为输入(根据下面的错误日志)。如果我只是使用非自动样式的实例化代码(标记),那么它编译得很好。

我正在使用 gcc 5.4.1 设置(CMAKE_CXX_STANDARD 11)设置。我也试过 14 和 17,所以我认为它不是我正在使用的 cpp。

【问题讨论】:

  • 如果类从不派生,那么使用虚拟析构函数毫无意义。 (如果你确实从这个类派生它会大大改变问题)
  • 这个类肯定是封装而不是派生的候选者吧?
  • 虚拟 dtor 的重点是确保基类的 dtor 被调用,这对于 std::unique_lock 很重要。
  • 你说的封装,和组合一样吗?为了简洁明了,我发送了一个玩具示例,但我的目的是在构建和销毁此类时进行一些记录以用于调试目的,因此它只是记录一些数据的唯一锁。
  • 基类的析构函数始终运行。 virtual 析构函数通过指向具有virtual 析构函数的父类的指针,确保在对象为deleted 时运行最派生类的析构函数。由于std::unique_lock 没有virtual 析构函数,如果A 通过指向std::unique_lock 的指针是deleted,您的析构函数将不会运行。

标签: c++ constructor virtual destructor auto


【解决方案1】:

如果您的类包含用户声明的析构函数、复制构造函数或赋值运算符,编译器不会隐式生成移动构造函数。由于A 没有move-constructor,编译器回退到copy-constructor,因为std::unique_lock 的copy-constructor 被删除,所以隐式删除。

您可以显式声明一个移动构造函数以使事情正常运行:

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

您可能还应该声明一个移动赋值运算符,但在这种情况下这不是必需的。

【讨论】:

    猜你喜欢
    • 2012-09-28
    • 2019-08-07
    • 1970-01-01
    • 2013-06-23
    • 2011-09-27
    • 1970-01-01
    • 2012-12-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多