Tag: 语言律师

我真的需要为const对象实现用户提供的构造函数吗?

我有这个代码: class A { public: A() = default; private: int i = 1; }; int main() { const A a; return 0; } 它在g ++(见ideone )上编译得很好,但在clang ++上失败,出现错误: consttypes“const A”的对象的默认初始化需要用户提供的默认构造函数 我在LLVM bug跟踪器上报告了这个问题,并将其视为无效。 我认为试图说服铿锵的开发者绝对毫无意义。 另一方面,我看不出这种限制的原因。 任何人都可以build议,如果C ++ 11标准莫名其妙地暗示此代码是无效的? 或者我应该只是向g ++报告错误? 或者,也许在语言规则方面有足够的自由来处理这些代码?

是一个C程序所需的主要()?

那么标题说明了一切。 对于C程序来说, main()函数是绝对必要的吗? 我问这是因为我在看Linux内核代码,而我没有看到main()函数。

在std :: array初始化中使用Brace elision

假设有一个std::array被初始化。 没关系,如果使用双花括号: std::array<int, 2> x = {{0, 1}}; std::array<int, 2> x{{0, 1}}; 在旧的聚合初始化中使用单个大括号也是可以的,因为大括号将会照顾大括号: std::array<int, 2> x = {0, 1}; 但是,使用单个大括号进行列表初始化可以吗? GCC接受它,Clang拒绝使用“在使用直接列表初始化时,不能忽略子对象初始化时的括号”。 std::array<int, 2> x{0, 1}; 提到大括号的唯一部分是8.5.1 / 12,它说: 使用赋值expression式初始化聚合成员时,将考虑所有隐式types转换(第4章)。 如果赋值expression式可以初始化一个成员,则该成员被初始化。 否则,如果该成员本身是一个子集合,则假定支撑精确,并且为该子集合的第一个成员的初始化考虑赋值expression式。 8.5.1是关于具体的聚合初始化的,所以应该表示铿锵拒绝是正确的吧? 没那么快 8.5.4 / 3说: Ttypes的对象或引用的列表初始化定义如下: […] – 否则,如果T是聚合,则执行聚合初始化(8.5.1)。 我认为这意味着与汇总初始化(包括大括号)一样的规则也适用,这意味着GCC是正确的接受。 我承认,措辞不是特别清楚。 那么,哪个编译器对待第三个片段是正确的呢? 大括号是否在列表初始化中发生,或者不是?

是std :: vector <T>一个`用户定义的types`?

在当前标准草案的 17.6.4.2.1 / 1和17.6.4.2.1 / 2中,对用户注入namespace std专门化进行了限制。 除非另有说明,否则C ++程序的行为是未定义的,如果它将声明或定义添加到名称空间std或名称空间std中的名称空间。 只有当声明依赖于用户定义的types ,并且专业化符合原始模板的标准库要求并且没有明确禁止时,程序可以将任何标准库模板的模板专用化添加到名称空间std。 我无法find标准中用户定义types定义的词组。 我听说一个选项声称是一个不是std::is_fundamental types是一个用户定义的types ,在这种情况下, std::vector<int>将是一个用户定义的types 。 另一个答案是用户定义的types是用户定义的types 。 由于用户没有定义std::vector<int> ,而std::vector<int>不依赖于用户定义的任何types,所以std::vector<int>不是用户定义的types 。 这个影响的一个实际问题是“你可以为std::tuple<Ts…>注入一个std::hash的专门化到namespace std吗?能够这样做有点方便 – 另一种方法是创build另一个名称空间我们recursion地构build我们的std::tuple (也可能是std中没有hash支持的其他types)的hash ,当且仅当我们无法在那个名字空间中find散列时,我们才回退std 。 但是,如果这是合法的,那么如果标准为std::tuple添加了一个hash专门化到namespace std ,已经被专门化的代码将被破坏,创build一个不会在未来添加这样的专业化的理由。 虽然我正在谈论作为一个具体的例子std::vector<int> ,我想问是否std中定义的types是用户定义的types s。 第二个问题是,即使没有,也许std::tuple<int>在用户使用时变成了一个用户定义的types (这会变得很滑:如果std内的东西定义了std::tuple<int> ,那么会发生什么呢?你对std::tuple<Ts…>进行部分hash )。 目前在这个问题上有一个公开的缺陷 。

运营商的负指数是否定义良好?

我知道这将是非常糟糕的编码风格,但下面的代码在我的机器上完美运行。 但是,行为是否明确? 便携式? int main() { int *p = new int[3]; int *q = &p[2]; q[-1] = 41; std::cout << p[1]; delete[] p; }

理解混淆typedef语法

考虑下面的代码片段 typedef int type; int main() { type *type; // why is it allowed? type *k ;// which type? } 我得到一个错误'k' is not declared in this scope 。 编译器将type *kparsing为type*和k之间的乘法。 这个语法不是很混乱吗? 为什么是C ++标准允许的type *type ? 因为语法是这样说的? 为什么?

C和C ++标准之间的关系是什么?

我正在写这个答案 ,我引用http://en.cppreference.com/w/cpp/string/byte/tolower#Parameters 不能表示为无符号字符,并不等于EOF,行为是未定义的 当我去检查添加了这个短语的编辑时,我发现作者的评论: 不能使用每个C99 7.4 / 1的任何ctype.h函数的带负号的字符 作者引用C ++文档中的C99标准。 这有效吗? 在C ++标准中,我找不到这个函数的定义,所以我必须假定它是有效的。 但是这个问题有两个原因: 我怎么知道C ++标准依赖于什么版本的C标准? 有C和C ++之间的差异列表。 如果我参照C ++来看C标准,我怎么可能知道我所看到的区域是否被覆盖了?

为什么我= v 未定义?

从C ++(C ++ 11)标准,讨论评估顺序的§1.9.15,是以下代码示例: void g(int i, int* v) { i = v[i++]; // the behavior is undefined } 如代码示例中所述,行为是未定义的。 (注:另一个问题的答案与i + i++略有不同, 为什么a = i + i ++未定义而不是未指定的行为 , 可能适用于此:答案本质上是由于历史原因行为未定义,而不是然而,这个标准似乎暗示了一些没有定义的理由 – 参见下面的引用,而且,这个相关的问题表明同意这个行为应该是不确定的 ,而在这个问题中,我问的是为什么这个行为不是很好,指定) 。 标准给出的未定义行为的推理如下: 如果对标量对象的副作用相对于同一个标量对象的另一个副作用或者使用相同标量对象的值进行值计算而言是不确定的,则行为是不确定的。 在这个例子中,我认为子expression式i++在评估子expression式v[…] 之前将被完全评估,并且子expression式的评估结果是i (在增量之前),但是i的值是该子expression式之后的递增值已被完全评估。 我认为在那个时候(在子expression式i++被完全评估之后),评估v[…]发生,然后是指派i = … 因此,虽然i的增加毫无意义,但我仍然认为这应该被定义 。 为什么这个未定义的行为?

C不检查指针是否检查指针是否超出范围?

我和一些人说过,即使C没有被解除引用,C的out-of-bound指针也会导致未定义的行为。 例: int a; int *p = &a; p = p – 1; 这里的第三行会导致未定义的行为,即使p永远不会被解除引用( *p永远不会被使用)。 在我看来,如果没有使用指针,C会检查指针是否超出范围,这听起来是不合逻辑的(就像有人会检查街上的人看他们是否携带枪支,以防他们进入他的房子。那些理想的事情就是在人们进入房子的时候检查他们)。 我认为,如果C检查,那么会发生很多运行时间的开销。 另外,如果C真的检查OOB指针,那么为什么这不会导致UB: int *p; // uninitialized thus pointing to a random adress 在这种情况下,即使指向OOB地址的机会很高,为什么什么也不会发生。 加: int a; int *p = &a; p = p – 1; 说&a是1000.评估第三行后p的值是: 996,但仍然是未定义的行为,因为p可能在其他地方被解引用并导致真正的问题。 未定义的值 ,这是未定义的行为。 因为我认为“第三行被称为”未定义的行为“首先是因为将来可能会使用OOB指针(取消引用)和人,随着时间的推移,它将其作为一个未定义的行为。 现在, p的值是100%还是996 ,还有未定义的行为或者它的值是不确定的?

ECMAScript规范中的“新对象”与“对象”

所以,我正在看什么new Object和Object的定义ES5规范。 出乎我的意料: new Object描述了对象构造函数如何工作的整个algorithm – 处理不同types的值会发生什么。 基本上在非对象上调用ToObject – 在对象上标识,并build立在null和undefined。 Object有一个特殊的第一步为空和未定义的地方,它build立一个对象,然后调用对象基元上的ToObject和身份。 几次阅读说明后 – 看起来完全相同。 不过,从规格上来看,他们做了一些不同的事情 。 例如在Array – 调用new Array被指定为函数调用Array(…)等价于具有相同参数的对象创buildexpression式new Array(…) 。 所以 – new Object和Object什么区别? 为什么他们有不同的指定? 为了方便 – 这是一个链接到规范 。