禁用 CRTP 模板中的复制分配

Posted

技术标签:

【中文标题】禁用 CRTP 模板中的复制分配【英文标题】:Disable copy assigment in CRTP-template 【发布时间】:2021-10-22 19:01:42 【问题描述】:

我有一个CRTP 模板,我在其中使用了一个对象池。使用 generate() 静态方法分配对象。

template <class tDerivedSignal, class tBridgeType, class tPayLoadType = void>
    class SignalT : public SignalSignatureT<tBridgeType>
   
   ...
   static tDerivedSignal &generate(tPayLoadType &fPayLoad)
      
      tDerivedSignal &rtnVal = Pool::reserve();

      // Copy pay load to signal instance
      rtnVal.mPayLoad = fPayLoad;

      // Return generated signal
      return(rtnVal);
      
   ...
   

现在,问题是我不想阻止像这样的复制分配

DerivedSignal sig = DerivedSignal::generate()

原因是副本 sig 可能具有本地范围并变得无效/被破坏,这将在以后用户尝试使用它时产生段错误.此外,分配的池对象将丢失并泄漏内存。我希望上面的复制分配生成编译时错误,但引用分配例如

DerivedSignal &sig = DerivedSignal::generate()

应该没问题。我试图删除 CRTP 模板中的赋值运算符,但没有成功:

template <class tDerivedSignal, class tBridgeType, class tPayLoadType = void>
    class SignalT : public SignalSignatureT<tBridgeType>
   
   ...
   // Disable copy assignment operator to prevent a generated signal from being copied into
   // a new instance that is not under pool management
   tDerivedSignal operator=(const tDerivedSignal &) = delete;
   tDerivedSignal operator=(const tDerivedSignal) = delete;
   ...
   

有人知道吗?

【问题讨论】:

不是赋值,是复制构造。你想要tDerivedSignal(const tDerivedSignal&amp;) = delete; 我最初的想法相同,但在 GCC 4.7 上无法编译。我在“const”之前得到“预期的不合格 ID” 哦,抱歉,被代码中的某些东西弄糊涂了,复制构造(以及通常的复制赋值)是在当前类型上完成的,所以你只需要SignalT(cont SignalT) = delete 您不应该忽略您使用 GCC 4.7。它对 C++11 的支持仍处于试验阶段。我们提供的有效 C++11 建议可能不起作用。 这也是不行的,因为(我相信)复制构造删除仅适用于 SignatT 类型而不适用于派生类型。如果我这样做 DerivedSignal(const DerivedSignal&) = delete;它可以工作,但这样会使模板的目的无效。 【参考方案1】:

您想要删除 SignalT 复制分配(并且很可能是复制构造)。默认情况下,任何继承自此的类(如在您的 CRTP 模式中)都将删除其默认的复制构造函数/复制赋值运算符,这也将禁止默认的移动构造/移动赋值运算符。

template <class tDerivedSignal, class tBridgeType, class tPayLoadType = void>
    class SignalT : public SignalSignatureT<tBridgeType>
   
   ...
   // Disable copy assignment operator to prevent a generated signal from being copied into
   // a new instance that is not under pool management
   
   void SignalT operator=(const SignalT&) = delete;

   // You probably also want to delete copy construction
   SignalT(SignalT const&) =delete;

   ...
   

【讨论】:

在我的一个小问题之后,以下工作:SignalT(SignalT const&amp;) = delete;SignalT() = default;SignalT operator=(const SignalT&amp;) = delete 在我的一个模板特化中给出了错误(无效的抽象返回类型)。 你想要返回 SignalT&,以避免这种情况,但老实说,当我删除赋值运算符时,我倾向于返回 void(从 C++03 天开始的习惯,当我会声明函数,但不定义它,并将其设为私有。

以上是关于禁用 CRTP 模板中的复制分配的主要内容,如果未能解决你的问题,请参考以下文章

如何禁用日历中的未来日期? [复制]

如何快速禁用 SkyFloatingLabelTextField 中的复制粘贴功能?

如何禁用html中的右键菜单? [复制]

如何禁用bash中的特殊字符? [复制]

AWS API Gateway REST API 是不是没有设置来禁用 CloudFormation 模板中的 execute-api 端点?

如何在 django 模板中的另一个字段中更改后禁用复选框?