请参阅B.Stroustrup第41.2.2节"TCPL"第4版的指令重新排序,我将在下面转录:
获得性能,编译器,优化器和硬件重新排序指令.考虑:
Run Code Online (Sandbox Code Playgroud)// thread 1: int x; bool x_init; void init() { x = initialize(); // no use of x_init in initialize() x_init = true; // ... }对于这段代码,没有明确的理由在分配给x_init之前分配给x.优化器(或硬件指令调度程序)可以通过首先执行x_init = true来决定加速程序.我们可能意味着x_init指示x是否已由initializer()初始化.但是,我们没有这么说,所以硬件,编译器和优化器都不知道.
向程序添加另一个线程:
Run Code Online (Sandbox Code Playgroud)// thread 2: extern int x; extern bool x_init; void f2() { int y; while (!x_init) // if necessary, wait for initialization to complete this_thread::sleep_for(milliseconds{10}); y = x; // ... }现在我们遇到了一个问题:线程2可能永远不会等待,因此会将未初始化的x分配给y.即使线程1未将x_init和x设置为"错误的顺序",我们仍然可能会遇到问题.在线程2中,没有对x_init的赋值,因此优化器可能决定将!x_init的求值提升到循环之外,以便线程2永远不会睡眠或永远睡眠.
作者的意思是"将!x_init的评估解除出来"?这是这样的吗?
if( !x_init ) while(true) this_thread::sleep_for(milliseconds{10});
y …Run Code Online (Sandbox Code Playgroud)标准中有哪些具体内容?我发现§9.2/ 10:Non-static (9.4) data members shall not have incomplete types. In particular, a class C shall not contain a non-static member of class C, but it can contain a pointer or reference to an object of class C.但这似乎并没有直接支持手头的问题.
#include <iostream>
struct A{
int i;
static A a;
};
A A::a{10};
int main() {
std::cout << A::a.i << '\n';
}
Run Code Online (Sandbox Code Playgroud) 这基本上是Item 21. Overriding Virtual FunctionsHerb Sutter的书中给出的例子的副本Exceptional C++.
#include <iostream>
#include <complex>
using namespace std;
class Base
{
public:
virtual void f(int);
virtual void f(double);
virtual ~Base() {};
};
void Base::f(int) { cout << "Base::f(int)" << endl; }
void Base::f( double ) { cout << "Base::f(double)" << endl; }
class Derived: public Base {
public:
void f(complex<double>);
};
void Derived::f(complex<double>) { cout << "Derived::f(complex)" << endl; }
int main()
{
Base* pb = new Derived;
pb->f(1.0); …Run Code Online (Sandbox Code Playgroud) 鉴于§3.5/ 4中的以下语句(强调我的)和§7.3.1.1/ 1中的注释[94],我想在一个具有外部链接的未命名命名空间中声明的实体的一个单独示例.
§3.5/ 4
未命名的命名空间或在未命名的命名空间中直接或间接声明的命名空间具有内部链接.所有其他名称空间都有外部链接.具有名称空间作用域的名称上面没有给出内部链接,如果是名称,则具有与封闭名称空间相同的链接
- 一个变量; 要么
- 功能; 要么
- 命名类(第9节),或在typedef声明中定义的未命名类,其中类具有用于链接目的的typedef名称(7.1.3); 要么
- 命名枚举(7.2),或在typedef声明中定义的未命名枚举,其中枚举具有用于链接目的的typedef名称(7.1.3); 要么
- 属于具有链接的枚举的枚举器; 要么
- 一个模板.
关于§7.3.1.1/ 1的注释[94]:
虽然未命名的命名空间中的实体可能具有外部链接,但它们实际上由其翻译单元唯一的名称限定,因此永远不会从任何其他翻译单元中看到.
我认为这是C++ 11标准中的(次要)缺陷.在[dcl.dcl]中我们有:
简单声明:
decl-specifier-seq opt init-declarator-list opt ;
该DECL说明符-SEQ不能是可选的.
例如,下面的代码片段无法编译:
x;
Run Code Online (Sandbox Code Playgroud)
如果我在这里是正确的,那么第8.3/1段的开头也应该改变:
从:
声明符列表出现在可选(第7节) decl-specifier-seq(7.1)之后.
至:
在decl-specifier-seq(7.1)之后出现一个声明符列表.
7.1.6.1/1包含以下声明(强调我的):
有两个cv限定符,const和volatile.如果cv-qualifier 出现在decl-specifier-seq中,则声明的init-declarator-list不应为空.
以上粗体语句的相关性是什么?换句话说,是否可以 在decl-specifier-seq中生成cv-unqualified类型的示例,其中声明的init-declarator-list为空?
从C++ 11标准的第5.2.2/1段中提取的句子中粗体字符是什么意思?
函数调用有两种:普通函数调用和成员函数(9.3)调用.函数调用是后缀表达式,后跟括号,其中包含可能为空的逗号分隔的表达式列表,这些表达式构成函数的参数.对于普通函数调用,后缀表达式应该是引用函数的左值(在这种情况下,函数到指针标准转换(4.3)在后缀表达式上被抑制),或者它应该具有指向函数类型的指针.
编辑
基本上我要问的是:当标准说"(在这种情况下,函数到指针标准转换在后缀表达式上被抑制)"这是否意味着这种抑制是好的或者它将在以后被撤销(例如,在函数重载之后)?
EDIT1
在我看来,上面的"抑制"一词具有误导性,因为它给人的印象是,从函数名到函数指针的转换可能永远不会被编译器完成.我相信情况并非如此.在函数重载过程完成后,此转换将始终发生,因为只有在此时,编译器才能确切地知道要调用的函数.程序初始化函数指针时不是这种情况.在这种情况下,编译器知道要调用的函数,因此不会出现重载,如下例所示.
#include <iostream>
int foo(int i) { std::cout << "int" << '\n'; return i * i; }
double foo(double d) { std::cout << "double" << '\n'; return d * d; }
int main()
{
int(*pf)(int) = foo; // no overloading here!
std::cout << pf(10.) << '\n'; // calls foo(int)
std::cout << foo(10.) << '\n'; // call foo(double) after function overloading. Therefore, only after function
// overloading is finished, the function name foo() …Run Code Online (Sandbox Code Playgroud) 该句是第3.2/2段的一部分:
名称显示为潜在评估表达式的变量是odr-used,除非它是满足出现在常量表达式(5.19)中的要求的对象,并且立即应用左值到右值转换(4.1).
粗体句子究竟是什么意思?
编辑:
这个被认为是重复的问题的答案,并没有说任何可以回答我的问题.
例如,在下面的代码片段中,C::operator A()隐式调用用户定义的转换函数,将类型的左值转换为类型C的prvalue A,它a在直接初始化中复制初始化变量.
struct A {};
struct C { operator A() { return A(); }; };
int main()
{
C c;
A a(c);
}
Run Code Online (Sandbox Code Playgroud)
我只是想知道C++ 14标准中描述的位置.我有一种感觉,答案在[over.match.copy]/1项目符号点(1.2)中,但我遇到了用户定义的转换复制初始化部分标题的问题.
c++ ×10
c++11 ×8
c++14 ×2
const ×1
copy-elision ×1
linkage ×1
namespaces ×1
optimization ×1
overloading ×1
overriding ×1
volatile ×1