Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
已删除默认构造函数。仍然可以创建对象。。。有时 天真,乐观,还有。。所以对c++11统一初始化语法的看法是错误的_C++_C++14_Language Lawyer_List Initialization_Aggregate Initialization - Fatal编程技术网

已删除默认构造函数。仍然可以创建对象。。。有时 天真,乐观,还有。。所以对c++11统一初始化语法的看法是错误的

已删除默认构造函数。仍然可以创建对象。。。有时 天真,乐观,还有。。所以对c++11统一初始化语法的看法是错误的,c++,c++14,language-lawyer,list-initialization,aggregate-initialization,C++,C++14,Language Lawyer,List Initialization,Aggregate Initialization,我认为,由于C++11用户定义的类型对象应该使用新的{…}语法而不是旧的(…)语法来构造(除了std::initializer\u list的构造函数重载和类似的参数(例如std::vector:size-ctor vs-elem-init\u-list-ctor)) 好处是:没有狭窄的隐式转换,没有最麻烦的解析问题,一致性(?)。我认为没有问题,因为我认为它们是一样的(除了给出的例子) 但事实并非如此 纯粹疯狂的故事 {}调用默认构造函数 。。。除非: 默认构造函数将被删除并删除 没有定义其

我认为,由于C++11用户定义的类型对象应该使用新的
{…}
语法而不是旧的
(…)
语法来构造(除了
std::initializer\u list
的构造函数重载和类似的参数(例如
std::vector
:size-ctor vs-elem-init\u-list-ctor))

好处是:没有狭窄的隐式转换,没有最麻烦的解析问题,一致性(?)。我认为没有问题,因为我认为它们是一样的(除了给出的例子)

但事实并非如此

纯粹疯狂的故事
{}
调用默认构造函数

。。。除非:

  • 默认构造函数将被删除并删除
  • 没有定义其他构造函数
然后它看起来像是它的值初始化了对象?。。。即使对象已删除默认构造函数,
{}
也可以创建对象。这不正是删除构造函数的全部目的吗

…除非:

  • 该对象具有已删除的默认构造函数和
  • 定义的其他构造函数
然后调用已删除的构造函数失败

…除非:

  • 该对象具有已删除的构造函数和
  • 没有定义其他构造函数,并且
  • 至少有一个非静态数据成员
然后由于缺少字段初始值设定项而失败

但是您可以使用
{value}
来构造对象

好的,也许这与第一个异常相同(对象的值init)

…除非:

  • 该类具有已删除的构造函数
  • 以及初始化类default中的至少一个数据成员
然后nor
{}
{value}
都不能创建对象

我肯定我错过了一些。讽刺的是,它被称为统一初始化语法。我再说一遍:UNIFORM初始化语法

这是什么疯狂

情景A 已删除默认构造函数: 情景B 已删除默认构造函数,其他构造函数已删除 情景C 已删除默认构造函数,已定义其他构造函数 情景D 已删除默认构造函数,未定义其他构造函数,数据成员 情景E 已删除默认构造函数、已删除T构造函数、T数据成员 情景F 已删除默认构造函数、类内数据成员初始值设定项
当以这种方式看待事物时,很容易说在初始化对象的方式中存在着完全和彻底的混乱

最大的区别来自
foo
的类型:它是否是聚合类型

如果有以下情况,则为聚合:

  • 没有用户提供的构造函数(已删除或默认的函数不算作用户提供的)
  • 没有私有或受保护的非静态数据成员

  • 非静态数据成员没有大括号或相等的初始值设定项(从c++11到(在c++14中恢复)
  • 没有基类
  • 没有虚拟成员函数
因此:

  • 在场景A B D E:
    foo
    是一个聚合
  • 在场景C中:
    foo
    不是聚合
  • 情景F:
    • 在c++11中,它不是聚合
    • 在c++14中,它是一个聚合
    • g++没有实现这一点,即使在C++14中,它仍然将其视为非聚合。
      • 4.9
        没有实现这一点
      • 5.2.0
      • 5.2.1 ubuntu
        没有(可能是回归)
类型为T的对象的列表初始化的效果如下:

  • 如果T是聚合类型,则执行聚合初始化。这将考虑场景A B D E(和C++14中的F)
  • 否则,T的施工人员将分两个阶段考虑:
    • 接受std::initializer\u列表的所有构造函数
    • 否则[…]T的所有构造函数都参与重载解析[…]这将处理C(以及C++11中的F)
:

T类型对象的聚合初始化(场景A B D E(F c++14)):

  • 每个非静态类成员在类定义中的顺序外观都是从 初始化列表。(省略数组引用)

TL;DR

所有这些规则看起来仍然非常复杂,令人头痛。我个人对此过于简化(如果我因此射中了自己的脚,那就这样吧:我想我会在医院里呆两天,而不是头痛几十天):

  • 对于聚合,从列表初始值设定项的元素初始化每个数据成员
  • else调用构造函数

这不正是删除构造函数的全部目的吗

我不知道,但解决办法是让
foo
不是一个聚合。不增加开销且不改变对象所用语法的最常见形式是使其从空结构继承:

struct dummy_t {};

struct foo : dummy_t {
  foo() = delete;
};

foo f{}; // ERROR call to deleted constructor
在某些情况下(我想根本没有非静态成员),替代方法是删除析构函数(这将使对象在任何上下文中都不可实例化):


此答案使用从以下方面收集的信息:

非常感谢帮助纠正和改进这篇文章的人。

把你搞砸的是聚合初始化

正如您所说,使用列表初始化有其优点和缺点。“统一初始化”一词不被C++标准使用。 缺点之一是聚合的列表初始化行为与非聚合不同。还有,定义
struct foo {
  foo() = delete;
  foo(int) = delete;
};

foo f{}; // OK
struct foo {
  foo() = delete;
  foo(int) {};
};

foo f{}; // error call to deleted constructor
struct foo {
  int a;
  foo() = delete;
};

foo f{}; // error use of deleted function foo::foo()
foo f{3}; // OK
struct foo {
  int a;
  foo() = delete;
  foo(int) = delete;
};

foo f{}; // ERROR: missing initializer
foo f{3}; // OK
struct foo {
  int a = 3;
  foo() = delete;
};

/* Fa */ foo f{}; // ERROR: use of deleted function `foo::foo()`
/* Fb */ foo f{3}; // ERROR: no matching function to call `foo::foo(init list)`
struct dummy_t {};

struct foo : dummy_t {
  foo() = delete;
};

foo f{}; // ERROR call to deleted constructor
struct foo {
  ~foo() = delete;
};

foo f{}; // ERROR use of deleted function `foo::~foo()`
struct X {
    X() = delete;
  };

 int main() {
    X x1;   // ill-formed - default c’tor is deleted
    X x2{}; // compiles!
}
struct X {
  private:
    X() = default;
  };

int main() {
    X x1;     // ill-formed - default c’tor is private
    X x2{};  // compiles!
  }
 static_assert(!std::is_default_constructible_v<X>);