问题标签 [rule-of-zero]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
0 回答
63 浏览

c++ - 规则 5 - 编译时不使用赋值运算符

为了在处理数组成员时理解移动运算符,我编写了以下开发测试。

当我通过不实现赋值或移动赋值运算符而违反了 5 规则时,为什么这会起作用和/或编译?

我目前正在使用 Visual Studio 2015。

0 投票
1 回答
82 浏览

c++ - 如何正确地将规则 5(或零?)应用于包含带有字符串的自定义对象向量的类

我无法将我的大脑围绕所有权和通过动作最大化性能。想象一下这组假想的类模拟 Excel 工作簿。

等等:

  • 工作表类将包含行向量
  • Workbook 类将包含 Worksheets 的向量

我觉得没有必要为 MWE 实现最后两个,因为它们实际上是 Row 的重复(我的假设是它们与 Row 的设计相同)。

我很难理解是否可以依赖默认值,或者我是否应该定义自己的移动构造函数(而不是保持默认值)以确保私有向量成员变量被移动而不是被复制,但这一切都非常令人困惑对我来说,我似乎只能找到一个除了内置类型成员之外什么都没有的类的过于简单化的例子。

0 投票
1 回答
102 浏览

c++ - 用“= default”声明复制构造函数或根本不声明它有什么区别?

我试图了解各种功能的自动生成编译器代码的行为,例如:

  1. 析构函数
  2. 复制构造函数
  3. 赋值运算符
  4. 移动构造函数
  5. 移动赋值运算符

与未声明的情况相比,使用“= default”声明它们会导致任何功能差异吗?这个问题的答案在上面列出的函数中是否有所不同?如果没有功能差异,使用这两种情况的后果是什么?

使用“= default”声明的复制构造函数

未声明复制构造函数:

0 投票
1 回答
124 浏览

c++ - 零规则 - 未生成默认构造函数

我在读这个:https ://en.cppreference.com/w/cpp/language/rule_of_three

我对此的理解是,如果你想拥有一个带有虚拟析构函数的基类,你需要定义所有 5 个特殊函数(从 0 部分的规则中提取):

但是,当我尝试创建该类时,我收到错误消息,提示“未创建默认 c'tor”:

然后,如果我生成默认值就可以了:

但我根本不明白这是需要的......所以我很困惑为什么它不在那里。我认为编译器不生成默认构造函数的唯一原因是如果您指定了非默认构造函数......

如果您确实需要指定默认 c'tor,那么示例中的类是不可构造的 - 这看起来很奇怪。

这是我的完整示例的链接:https ://godbolt.org/z/qPvjd6r51


https://en.cppreference.com/w/cpp/language/default_constructor

隐式声明的默认构造函数

如果没有为类类型(结构、类或联合)提供任何类型的用户声明的构造函数,编译器将始终将默认构造函数声明为其类的内联公共成员。

我想这意味着如果base_of_five_defaults(const base_of_five_defaults&) = default;声明了,那么即使它的“默认”也被认为是用户声明的?

0 投票
0 回答
75 浏览

c++ - 零规则如何影响具有隐藏可见性的共享库?

注意:问题在底部。

我试图了解如果将零规则与共享库和派生类型一起使用可能会出现的问题。

在下面的演示中,DerivedType是否使用零规则编译取决于预处理器定义。该脚本随后演示了出现的差异,即如果DerivedType在 cpp 文件中定义了密钥方法,则仅在共享库中发出 vtable,而如果没有密钥方法,则在每个消费 TU 中发出 vtable。

baselib.h:

基础库.cpp

其他lib.h:

其他lib.cpp

主文件

使用 g++ 输出:

注意:这是问题:

如果在多个 TU 和共享库中发出 vtables,是否有某种模式dynamic_cast会失败,或者其他一些可能难以调试的失败模式?

0 投票
0 回答
120 浏览

c++ - 根据构造函数实现 C++ 赋值运算符

背景

假设您想在 C++ 中实现一个资源管理类。您不能使用规则或五个默认规则,因此您实际上需要实现复制和移动构造函数、复制和移动赋值运算符和析构函数。在这个问题中,我将Box用作示例,但这可以适用于许多不同的类型。

(请注意,更好的Box实现将具有更多的特性,例如noexceptconstexpr函数、explicit基于构造函数的转发构造value_type函数、分配器支持等;这里我正在实现问题和测试所必需的东西。它还可以使用 保存一些代码std::unique_ptr,但这会使它成为一个不太清楚的例子)

请注意,赋值运算符彼此共享大量代码,与它们各自的构造函数和析构函数共享。如果我不想让分配到从Boxen 移动,这会有所减轻,但在更复杂的类中会更明显。

题外话:复制和交换

处理此问题的一种标准方法是使用Copy-And-Swap Idiom(在此上下文中也称为“四半规则”)swap ,如果是,它还可以为您提供强有力的异常保证nothrow

这允许您只编写一个赋值运算符(other如果可能,按值取值让编译器将另一个移动到参数,并在必要时为您进行复制),并且该赋值运算符很简单(假设您已经拥有swap)。但是,正如链接文章所说,这存在诸如在操作期间进行额外分配和保留内容的额外副本等问题。

理念

我以前没有见过的是我称之为销毁和初始化赋值运算符的东西。既然我们已经在构造函数中完成了所有工作,并且对象的分配版本应该与复制构造的对象相同,为什么不使用构造函数,如下所示:

这仍然像 Copy-and-Swap 那样进行额外分配,但仅在复制分配情况下而不是在移动分配情况下,并且它销毁 的一个副本后进行T,因此它不会在资源限制下失败。

问题

  1. 以前是否有人提出过这个建议,如果有,我可以在哪里阅读更多相关信息?
  2. 在某些情况下,这个 UB 是否Box是其他东西的子对象,或者它是否允许销毁和重建子对象?
  3. 这有什么我没有提到的缺点吗,比如不constexpr兼容?
  4. 当您不能只使用它们时,是否还有其他选项可以避免赋值运算符代码重用,例如这个和四点半规则= default