我刚刚在c ++ 03标准草案中发现以下段落与指向成员转换的指针相关.
4.11/2指向成员转换的指针
类型为"cv T类型的B成员的指针"的r值,其中B是类类型,可以转换为类型为"指向类型为cv T的D的成员的指针"的右值,其中D是派生类(如果B是不可访问的(第11条),D的模糊(10.2)或虚拟(10.1)基类,则需要这种转换的程序是不正确的.转换的结果引用与转换发生前指向成员的指针相同的成员,但它引用基类成员,就好像它是派生类的成员一样.结果引用D的D实例中的成员.由于结果具有类型"指向cv T类型D的成员的指针",因此可以用D对象取消引用它.结果与指向B成员的指针与D的B子对象取消引用的结果相同.
5.2.9/9 static_cast
类型"指向Cv1 T类型D的成员的指针"的rvalue可以转换为类型为"指向cv2 T类型B的成员的指针"的rvalue,其中B是D的基类(第10节),如果a从"指向T类型B的成员的指针"到"指向T类型D的成员的指针"的有效标准转换存在(4.11),并且cv2与cv1.63具有相同的cv资格或更高的cv资格)null成员指针值(4.11)被转换为目标类型的空成员指针值.如果类B包含原始成员,或者是包含原始成员的类的基类或派生类,则指向成员的结果指针指向原始成员.否则,演员的结果是不确定的.[注意:虽然B类不需要包含原始成员,取消引用成员指针的对象的动态类型必须包含原始成员; 见5.5.]
所以这是我的问题.如5.2.9/9所述,如果存在4.11/2中描述的有效转换,则指向D成员的指针可以转换为指向B成员的指针.这是否意味着如果有一个成员'm'的D不是从B继承的,那么成员'm'的指针不能被转换为指向B成员的指针类型?
class Base { };
class Derived : public Base
{
int a;
};
typedef int Base::* BaseMemPtr;
BaseMemPtr pa = static_cast<BaseMemPtr>(&Derived::a); // invalid, as per 5.2.9/9 ?
Run Code Online (Sandbox Code Playgroud)
在5.2.9/9的注释中,它还说尽管B类不需要包含原始成员,但是取消引用成员指针的对象的动态类型必须包含原始成员.
我对该段的措辞感到困惑.以上代码有效吗?
我搜索了网站,有一个类似的问题,c ++继承和成员函数指针,其答案仅涵盖了从指针转换为基类成员到指向派生类成员的情况.
struct A {
A(int) {}
};
struct B {
B(A) {}
};
int main() {
B b({0});
}
Run Code Online (Sandbox Code Playgroud)
构造出现b
以下错误:
In function 'int main()':
24:9: error: call of overloaded 'B(<brace-enclosed initializer list>)' is ambiguous
24:9: note: candidates are:
11:2: note: B::B(A)
10:8: note: constexpr B::B(const B&)
10:8: note: constexpr B::B(B&&)
Run Code Online (Sandbox Code Playgroud)
我期待B::B(A)
被召唤,为什么在这种情况下它是模棱两可的?
在C++和Double-Checked Locking的Perils中,有一些persudo代码可以正确地实现模式,这是作者建议的.见下文,
Singleton* Singleton::instance () {
Singleton* tmp = pInstance;
... // insert memory barrier (1)
if (tmp == 0) {
Lock lock;
tmp = pInstance;
if (tmp == 0) {
tmp = new Singleton;
... // insert memory barrier (2)
pInstance = tmp;
}
}
return tmp;
}
Run Code Online (Sandbox Code Playgroud)
我只是想知道第一个内存屏障是否可以在return语句的正上方移动?
编辑:另一个问题:在链接文章中,引用vidstige
从技术上讲,您不需要完全双向障碍.第一道屏障必须防止Singleton构造的向下迁移(通过另一个线程); 第二个障碍必须阻止pInstance初始化的向上迁移.这些被称为"获取"和"释放"操作,并且可以产生比硬件(例如Itainum)上的完全障碍更好的性能.
它说第二个障碍不需要是双向的,那么如何防止pInstance的赋值在该障碍之前被移动?即使第一个障碍可以阻止向上迁移,但另一个线程仍然有机会看到未初始化的成员.
编辑:我想我几乎明白第一道屏障的目的.正如sonicoder所指出的,当if返回true时,分支预测可能导致tmp为NULL.为了避免这个问题,必须有一个获取障碍,以防止在读取if之前读取tmp.
第一道屏障与第二道屏障配对以实现同步关系,因此它可以向下移动.
编辑:对于那些对这个问题感兴趣的人,我强烈建议阅读memory-barriers.txt.
下面是对ebco的简单测试,我在vc9和g ++上编译了它.两个编译器的输出不同.我想知道的是vc的行为是否符合要求.
#include <iostream>
class empty
{
};
class empty_one : public empty {};
class empty_two : public empty {};
class non_empty
: public empty_one
, public empty_two
{
};
int main()
{
std::cout << "sizeof(empty): " << sizeof(empty) << std::endl;
std::cout << "sizeof(empty_one): " << sizeof(empty_one) << std::endl;
std::cout << "sizeof(empty_two): " << sizeof(empty_two) << std::endl;
std::cout << "sizeof(non_empty): " << sizeof(non_empty) << std::endl;
std::cout << std::endl;
non_empty a[2];
void* pe10 = static_cast<empty*>(static_cast<empty_one*>(&a[0]));
void* pe20 = static_cast<empty*>(static_cast<empty_two*>(&a[0]));
std::cout << …
Run Code Online (Sandbox Code Playgroud) cpuid
用作序列化指令以防止在基准测试时执行ooo,因为基准指令的执行可能会在rdtsc
单独使用之前重新排序.我的问题是,是否依然可能下面的说明rdtsc
中之间的重新排序cpuid
和rdtsc
?由于rdtsc
不是序列化指令,指令可以在它周围自由重新排序?
N3243 1.10.21说
可以证明,正确使用互斥锁和memory_order_seq_cst操作以防止所有数据争用并且不使用其他同步操作的程序就像它们的组成线程执行的操作只是交错一样,每个值的计算都来自于在交错中对该对象的最后副作用.这通常被称为"顺序一致性".
这是否意味着对原子对象的任何seq_cst写入对于使用seq_cst排序读取原子对象的其他线程是否立即可见?