我试图检查哪里float
失去了精确表示大整数的能力。所以我写了这个小片段:
int main() {
for (int i=0; ; i++) {
if ((float)i!=i) {
return i;
}
}
}
Run Code Online (Sandbox Code Playgroud)
该代码似乎适用于所有编译器,但不包括clang。Clang生成一个简单的无限循环。上帝保佑。
可以吗?如果是,那是QoI问题吗?
是否允许编译器对此进行优化(根据C++ 17标准):
int fn() {
volatile int x = 0;
return x;
}
Run Code Online (Sandbox Code Playgroud)
这个?
int fn() {
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果是,为什么?如果没有,为什么不呢?
这里有一些关于这个主题的思考:当前编译器编译fn()
为放在堆栈上的局部变量,然后返回它.例如,在x86-64上,gcc创建了这个:
mov DWORD PTR [rsp-0x4],0x0 // this is x
mov eax,DWORD PTR [rsp-0x4] // eax is the return register
ret
Run Code Online (Sandbox Code Playgroud)
现在,据我所知,标准并没有说应该将一个局部volatile变量放在堆栈上.所以,这个版本同样好:
mov edx,0x0 // this is x
mov eax,edx // eax is the return
ret
Run Code Online (Sandbox Code Playgroud)
这里,edx
商店x
.但是现在,为什么要停在这里?由于edx
和eax
均为零,我们可以只说:
xor eax,eax // eax is the return, and x as well
ret
Run Code Online (Sandbox Code Playgroud)
我们转变 …
我已经检查了所有主要的编译器,sizeof(std::tuple<int, char, int, char>)
所有这些都是16。大概它们只是将元素按顺序放入元组,因此由于对齐而浪费了一些空间。
如果元组在内部像这样存储元素:int, int, char, char
,则其sizeof可能为12。
实现有可能执行此操作,还是该标准中的某些规则禁止这样做?
我一直在std::memcpy
用来规避严格的混叠很长一段时间.
例如,检查a float
,像这样:
float f = ...;
uint32_t i;
static_assert(sizeof(f)==sizeof(i));
std::memcpy(&i, &f, sizeof(i));
// use i to extract f's sign, exponent & significand
Run Code Online (Sandbox Code Playgroud)
但是,这次,我检查了标准,我还没有找到任何可以验证这一点的东西.我所发现的是这个:
对于平凡可复制类型T的任何对象(可能重叠的子对象除外),无论对象是否保持类型T的有效值,组成对象的基础字节([intro.memory])都可以复制到char,unsigned char或std :: byte([cstddef.syn])数组.40如果将该数组的内容复制回对象,则该对象应随后保持其原始值.[例如:
Run Code Online (Sandbox Code Playgroud)#define N sizeof(T) char buf[N]; T obj; // obj initialized to its original value std::memcpy(buf, &obj, N); // between these two calls to std?::?memcpy, obj might be modified std::memcpy(&obj, buf, N); // at this point, each subobject of obj of scalar …
c++ strict-aliasing undefined-behavior language-lawyer c++17
看下面这个简单的代码:
struct Point {
int x;
int y;
};
void something(int *);
int main() {
Point p{1, 2};
something(&p.x);
return p.y;
}
Run Code Online (Sandbox Code Playgroud)
我希望main
可以将返回值优化为return 2;
,因为something
它无法访问p.y
,只能返回的指针p.x
。
但是,没有一个主要的编译器会优化main
to 的返回值2
。上帝保佑。
如果仅允许访问,标准中是否存在可以something
修改的内容?如果是,这是否取决于标准布局?p.y
p.x
Point
如果我使用something(&p.y);
,该return p.x;
怎么办?
众所周知,在比较浮点值时必须小心.通常,==
我们使用一些基于epsilon或ULP的相等测试来代替使用.
但是,我想知道,有什么案例,使用时==
完全没问题吗?
看看这个简单的片段,哪些案例可以保证成功?
void fn(float a, float b) {
float l1 = a/b;
float l2 = a/b;
if (l1==l1) { } // case a)
if (l1==l2) { } // case b)
if (l1==a/b) { } // case c)
if (l1==5.0f/3.0f) { } // case d)
}
int main() {
fn(5.0f, 3.0f);
}
Run Code Online (Sandbox Code Playgroud)
注意:我已经检查了这个和这个,但它们不包括(全部)我的情况.
注2:似乎我必须添加一些加号信息,所以答案在实践中很有用:我想知道:
这是我在目前的标准草案中找到的唯一相关陈述:
浮点类型的值表示是实现定义的.[注意:本文档对浮点运算的准确性没有要求; 另见[support.limits]. - 结束说明]
那么,这是否意味着甚至"案例a)"是实现定义的?我的意思是,l1==l1
绝对是一个浮点运算.那么,如果一个实现是"不准确的",那么可能l1==l1
是假的?
我认为这个问题不是重复的浮点数==永远好吗?.这个问题没有解决我提出的任何案件.同一主题,不同的问题.我想特别针对案例a)-d)得到答案,因为我无法在重复的问题中找到答案.
c++ floating-point precision language-lawyer floating-point-comparison
假设我有一个向量:
std::vector<Foo> v;
Run Code Online (Sandbox Code Playgroud)
此向量已排序,因此相等的元素彼此相邻。
获得所有表示具有相等元素的范围的迭代器对的最佳方法是什么(使用标准库)?
while (v-is-not-processed) {
iterator b = <begin-of-next-range-of-equal-elements>;
iterator e = <end-of-next-range-of-equal-elements>;
for (iterator i=b; i!=e; ++i) {
// Do something with i
}
}
Run Code Online (Sandbox Code Playgroud)
我想知道如何在上面的代码中获取b
和的值e
。
因此,例如,如果v
包含以下数字:
index 0 1 2 3 4 5 6 7 8 9
value 2 2 2 4 6 6 7 7 7 8
Run Code Online (Sandbox Code Playgroud)
然后,我想在循环中具有b
并e
指向元素:
iteration b e
1st 0 3
2nd 3 4
3rd 4 6
4th 6 9
5th …
Run Code Online (Sandbox Code Playgroud) 在答案/sf/answers/49319791/中,引用了Stroustrup:
C++显然允许delete的实现将左值操作数归零,我曾希望实现会这样做,但这个想法似乎并没有受到实现者的欢迎.
但是,我没有在标准中找到这个明确的陈述.目前的标准草案(N4659)中有一部分可以用这种方式解释:
6.7:
当达到存储区域的持续时间结束时,表示该存储区域的任何部分的地址的所有指针的值变为无效指针值(6.9.2).通过无效指针值间接并将无效指针值传递给释放函数具有未定义的行为.对无效指针值的任何其他使用都具有实现定义的行为.
脚注:某些实现可能会定义复制无效指针值会导致系统生成的运行时错误
因此,在a之后delete ptr;
,ptr
s值变为无效指针值,并且使用此值具有实现定义的行为.但是,它并没有说ptr
允许改变价值.
这可能是一个哲学问题,如果一个人不能使用它的价值,怎么能决定一个价值发生了变化呢?
6.9:
对于普通可复制类型T的任何对象(基类子对象除外),无论对象是否保持类型T的有效值,构成对象的基础字节(4.4)都可以复制到char数组中, unsigned char,或std :: byte(21.2.1).43如果将该数组的内容复制回对象,该对象应随后保持其原始值.
所以,似乎它对memcpy
一个char数组的无效指针值是有效的(取决于哪个语句是"更强",6.7或6.9.对我来说,6.9似乎更强).
这样,我可以通过以下方式检测到指针值已被改变delete
:memcpy
指向delete
to char数组之前和之后的值,然后比较它们.
所以,据我所知,6.7 delete
不允许允许修改其参数.
是否允许删除修改其参数?
看看这里的评论:https: //stackoverflow.com/a/45142972/8157187
这是一个不太可能但仍然可能的现实世界代码,其中重要的是:
SomeObject *o = ...; // We have a SomeObject
// This SomeObject is registered into someHashtable, with its memory address
// The hashtable interface is C-like, it handles opaque keys (variable length unsigned char arrays)
delete o; …
Run Code Online (Sandbox Code Playgroud) 这是复制构造函数[class.copy.ctor / 1]的定义:
如果类X的非模板构造函数的第一个参数为X&,const X&,volatile X&或const volatile X&类型,并且没有其他参数,或者所有其他参数都具有默认参数([dcl。 fct.default])。
为什么标准将模板排除为复制构造函数?
在这个简单的示例中,两个构造函数都是副本构造函数:
struct Foo {
Foo(const Foo &); // copy constructor
Foo(Foo &); // copy constructor
};
Run Code Online (Sandbox Code Playgroud)
参见以下类似示例:
struct Foo {
Foo() = default;
template <typename T>
Foo(T &) {
printf("here\n");
}
};
int main() {
Foo a;
Foo b = a;
}
Run Code Online (Sandbox Code Playgroud)
在此示例中,here
将被打印。因此,似乎我的模板构造函数是一个复制构造函数,至少它的行为类似于一个(在通常调用复制构造函数的上下文中被调用)。
为什么文本中存在“非模板”要求?
请参阅以下示例:
struct Foo {
int a;
int &b = a;
};
Run Code Online (Sandbox Code Playgroud)
如果错过了优化sizeof(Foo)!=sizeof(int)
吗?
我的意思是,编译器可以b
从其始终引用的结构中删除它a
吗?
有什么阻止编译器进行这种转换的吗?
(请注意,struct Foo
看起来是这样。没有构造函数,等等。但是您可以在周围添加任何内容Foo
,这表明该优化将违反标准。)