C++规范是否定义:
换句话说,是否由规范定义的以下操作的结果?
false < false
false < true
true < false
true < true
Run Code Online (Sandbox Code Playgroud)
在我的设置(Centos 7,gcc 4.8.2)中,下面的代码吐出我期望的内容(假设C的历史表示false为0,true为1):
false < false = false
false < true = true
true < false = false
true < true = false
Run Code Online (Sandbox Code Playgroud)
虽然我很确定大多数(所有?)编译器会提供相同的输出,这是否由C++规范立法?或者是一个混淆但符合规范的编译器允许判断true是否小于false?
#include <iostream>
const char * s(bool a)
{
return (a ? "true" : "false");
}
void test(bool a, bool b)
{
std::cout << s(a) << " < " << s(b) << " = " << s(a < b) << std::endl; …
Run Code Online (Sandbox Code Playgroud) C11 标准似乎暗示不应优化带有常量控制表达式的迭代语句。我从这个答案中得到了我的建议,它特别引用了标准草案中的第 6.8.5 节:
其控制表达式不是常量表达式的迭代语句......可能会被实现假定为终止。
在该答案中,它提到while(1) ;
不应进行优化之类的循环。
那么……为什么 Clang/LLVM 优化了下面的循环(用 编译cc -O2 -std=c11 test.c -o test
)?
#include <stdio.h>
static void die() {
while(1)
;
}
int main() {
printf("begin\n");
die();
printf("unreachable\n");
}
Run Code Online (Sandbox Code Playgroud)
在我的机器上,这会打印出begin
,然后在非法指令(ud2
放置在 之后的陷阱die()
)上崩溃。在 Godbolt 上,我们可以看到调用puts
.
让 Clang 输出无限循环是一项非常困难的任务-O2
- 虽然我可以反复测试一个volatile
变量,但这涉及到我不想要的内存读取。如果我做这样的事情:
#include <stdio.h>
static void die() {
while(1)
;
}
int main() {
printf("begin\n");
volatile int x …
Run Code Online (Sandbox Code Playgroud) 在回答的过程中的另一个问题,我偶然发现稍有不同的措辞为std::vector::erase()
和std::deque::erase()
.
这就是C++ 14所说的std::deque::erase
([deque.modifiers]/4-6
强调我的):
效果: ......
复杂性:对析构函数的调用次数与擦除的元素数相同,但对赋值运算符的调用次数不超过删除元素之前的元素数量和次要元素数量之后的次数.擦除元素.
抛出:除非复制构造函数,移动构造函数,赋值运算符或移动赋值运算符抛出异常,否则无效
T
.
以下是关于std::vector::erase
([vector.modifiers]/3-5
)的内容:
效果: ......
复杂性:的析构函数
T
被调用的次数等于擦除的元件的数量的数量,但该移动赋值运算符的T
被称为的次数等于在向量元素的擦除元件后的数目的数目.抛出:除非复制构造函数,移动构造函数,赋值运算符或移动赋值运算符抛出异常,否则无效
T
.
正如您所看到的,两者的异常规范是相同的,但是为了std::vector
明确提到它,调用了移动赋值运算符.
还有的要求T
是MoveAssignable
对erase()
两者的工作std::vector
和std::deque
(表100),但这并不意味着移动赋值运算符的存在:一个可以定义一个拷贝赋值运算符,而不是定义移动赋值操作符,而这个班会是MoveAssignable
.
为了以防万一,我检查了GCC和Clang,std::vector::erase()
如果没有移动赋值运算符,确实调用了复制赋值运算符,并且std::deque::erase()
执行相同的操作(DEMO).
所以问题是:我错过了什么,或者这是标准中的(编辑)问题?
更新: 我已经提交了LWG问题#2477.
通过一些C面试问题,我找到了一个问题,指出“如何在不使用sizeof运算符的情况下在C中查找数组的大小?”,并提供以下解决方案。它有效,但是我不明白为什么。
#include <stdio.h>
int main() {
int a[] = {100, 200, 300, 400, 500};
int size = 0;
size = *(&a + 1) - a;
printf("%d\n", size);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如预期的那样,它返回5。
编辑:人们指出了这个答案,但是语法确实有所不同,即索引方法
size = (&arr)[1] - arr;
Run Code Online (Sandbox Code Playgroud)
因此,我认为这两个问题都是有效的,并且对该问题的解决方法略有不同。谢谢大家的大力帮助和详尽的解释!
根据Stack Overflow问题的接受(且唯一)答案,
使用定义构造函数
Run Code Online (Sandbox Code Playgroud)MyTest() = default;
而是将零初始化对象.
那为什么以下,
#include <iostream>
struct foo {
foo() = default;
int a;
};
struct bar {
bar();
int b;
};
bar::bar() = default;
int main() {
foo a{};
bar b{};
std::cout << a.a << ' ' << b.b;
}
Run Code Online (Sandbox Code Playgroud)
产生这个输出:
0 32766
Run Code Online (Sandbox Code Playgroud)
两个构造函数都是默认的?对?对于POD类型,默认初始化为零初始化.
根据这个问题的接受答案,
如果POD成员未在构造函数中初始化,也未通过C++ 11类内初始化,则默认初始化.
无论堆栈还是堆,答案都是一样的.
在C++ 98中(而不是之后),新的int()被指定为执行零初始化.
vector<int> v;
v.push_back(1);
v.push_back(v[0]);
Run Code Online (Sandbox Code Playgroud)
如果第二个push_back导致重新分配,则向量中对第一个整数的引用将不再有效.那么这不安全吗?
vector<int> v;
v.push_back(1);
v.reserve(v.size() + 1);
v.push_back(v[0]);
Run Code Online (Sandbox Code Playgroud)
这样可以安全吗?
出于某种原因,我偷偷进入了该类的.NET Framework源代码,Double
并发现声明==
是:
public static bool operator ==(Double left, Double right) {
return left == right;
}
Run Code Online (Sandbox Code Playgroud)
每个操作员都适用相同的逻辑.
我有一种情况,我希望 C++ switch 语句中的两种情况都落入第三种情况。具体来说,第二种情况会落入第三种情况,而第一种情况也会落入第三种情况,而不会经过第二种情况。
我有一个愚蠢的想法,尝试了一下,它奏效了!我将第二个箱子包裹在一个if (0) {
... }
. 它看起来像这样:
#ifdef __cplusplus
# include <cstdio>
#else
# include <stdio.h>
#endif
int main(void) {
for (int i = 0; i < 3; i++) {
printf("%d: ", i);
switch (i) {
case 0:
putchar('a');
// @fallthrough@
if (0) { // fall past all of case 1 (!)
case 1:
putchar('b');
// @fallthrough@
}
case 2:
putchar('c');
break;
}
putchar('\n');
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我运行它时,我得到了所需的输出:
0: ac
1: bc …
Run Code Online (Sandbox Code Playgroud) 每次有人delete[]
在这里问一个问题时,总会有一个非常笼统delete[]
的回答:“ C++ 就是这样做的,使用”。来自普通的 C 背景,我不明白为什么需要一个不同的调用。
使用malloc()
/free()
您的选择是获取指向连续内存块的指针并释放连续内存块。实现领域中的某些东西会根据基地址知道您分配的块的大小,以便您何时必须释放它。
没有功能free_array()
。我在与此相关的其他问题上看到了一些疯狂的理论,例如调用delete ptr
只会释放数组的顶部,而不是整个数组。或者更正确的是,它不是由实现定义的。当然……如果这是 C++ 的第一个版本,并且您做出了一个有意义的奇怪设计选择。但是为什么 with$PRESENT_YEAR
的 C++ 标准没有被重载???
似乎 C++ 添加的唯一额外的一点是遍历数组并调用析构函数,我认为这可能是它的症结所在,它实际上是使用一个单独的函数来为我们节省单个运行时长度查找,或者nullptr
在列表的末尾,以换取折磨每个新的 C++ 程序员或程序员,他们有一个模糊的一天并且忘记了有一个不同的保留字。
如果除了“这就是标准所说的并且没有人质疑它”之外还有其他原因,有人可以一劳永逸地澄清吗?
auto foo = "You're using g++!";
auto compiler_detector = [foo](auto foo) { std::puts(foo); };
compiler_detector("You're using clang++!");
Run Code Online (Sandbox Code Playgroud)
clang ++ 3.6.0和更新的打印出"你正在使用clang ++!" 并警告捕获 foo
未被使用.
g ++ 4.9.0和更新版本打印出"你正在使用g ++!" 并警告该参数 foo
未被使用.
什么编译器更准确地遵循C++标准?