小编Eri*_*c Z的帖子

理解C++ 11中的std :: atomic :: compare_exchange_weak()

bool compare_exchange_weak (T& expected, T val, ..);
Run Code Online (Sandbox Code Playgroud)

compare_exchange_weak()是C++ 11中提供的比较交换原语之一.它在某种意义上很弱,即使对象的值等于它也会返回false expected.这是由于某些平台上的虚假故障导致一系列指令(而不是x86上的指令)用于实现它.在这样的平台上,上下文切换,由另一个线程重新加载相同的地址(或高速缓存行)等可能使原语失败.这是spurious因为它不是expected操作失败的对象(不等于)的值.相反,这是一种时间问题.

但让我感到困惑的是C++ 11标准(ISO/IEC 14882)中所说的,

29.6.5 ..虚假失败的后果是几乎所有弱比较和交换的使用都将处于循环中.

为什么几乎所有用途都必须处于循环中?这是否意味着我们会因为虚假失败而失败?如果是这样的话,为什么我们compare_exchange_weak()自己打扰使用并编写循环?我们可以使用compare_exchange_strong()我认为应该摆脱我们的虚假失败.有哪些常见用例compare_exchange_weak()

另一个问题有关.安东尼在他的书"C++ Concurrency In Action"中说,

//Because compare_exchange_weak() can fail spuriously, it must typically
//be used in a loop:

bool expected=false;
extern atomic<bool> b; // set somewhere else
while(!b.compare_exchange_weak(expected,true) && !expected);

//In this case, you keep looping as long as expected is still false,
//indicating that the compare_exchange_weak() …
Run Code Online (Sandbox Code Playgroud)

c++ multithreading atomic c++11

77
推荐指数
4
解决办法
2万
查看次数

我应该担心指针投射过程中的对齐吗?

在我的项目中,我们有一段这样的代码:

// raw data consists of 4 ints
unsigned char data[16];
int i1, i2, i3, i4;
i1 = *((int*)data);
i2 = *((int*)(data + 4));
i3 = *((int*)(data + 8));
i4 = *((int*)(data + 12));
Run Code Online (Sandbox Code Playgroud)

我和我的技术负责人谈到这个代码可能不便携,因为它试图将a unsigned char*转换为int*通常具有更严格的对齐要求的代码.但是技术主管说没关系,大多数编译器在转换后仍保持相同的指针值,我可以像这样编写代码.

坦率地说,我并不是真的相信.经过研究,我发现有些人反对使用上面的指针铸件,例如,这里这里.

所以这是我的问题:

  1. 在真实项目中投射后取消引用指针真的很安全吗?
  2. C型铸造和reinterpret_cast?之间有什么区别吗?
  3. C和C++之间有什么区别吗?

c c++ casting alignment

51
推荐指数
4
解决办法
1万
查看次数

为什么C/C++编译器在编译时需要知道数组的大小?

我知道C99之前的C标准(以及C++)说堆栈上的数组大小必须在编译时知道.但那是为什么呢?堆栈上的数组在运行时分配.那么为什么大小在编译时很重要?希望有人向我解释编译器在编译时将如何处理大小.谢谢.

这种数组的例子是:

void func()
{
    /*Here "array" is a local variable on stack, its space is allocated
     *at run-time. Why does the compiler need know its size at compile-time?
     */
   int array[10]; 
}
Run Code Online (Sandbox Code Playgroud)

c c++

37
推荐指数
3
解决办法
8971
查看次数

绕过定义时如何使用变量?

在我看来,定义总是意味着存储分配.

在以下代码中,int i在程序堆栈上分配一个4字节(通常)存储并将其绑定到i,i = 3并将3分配给该存储.但是因为goto,定义被绕过,这意味着没有分配存储空间i.

我听说局部变量在函数的入口处(f()在这种情况下)分配在它们所在的位置,或者在定义点处.

但无论哪种方式,如何i在尚未定义的情况下使用它(根本没有存储空间)?执行时分配给值3的位置在哪里i = 3

void f()
{
    goto label;
    int i;

label:
    i = 3;
    cout << i << endl; //prints 3 successfully
}
Run Code Online (Sandbox Code Playgroud)

c++ scope variable-declaration

36
推荐指数
4
解决办法
1038
查看次数

为什么在通过goto向后退出时会调用析构函数

可能重复:是否
会使用goto泄漏变量?

在下面的示例中,当goto调用"向后"时,A调用析构函数.为什么会那样?对象a不会离开它的范围,是吗?标准是否说明了这种行为goto

void f()
{
start:
    A a;
    goto start;
}
Run Code Online (Sandbox Code Playgroud)

c++

28
推荐指数
3
解决办法
1348
查看次数

内存重新排序是否对单处理器上的其他线程可见?

现代CPU架构通常采用可导致无序执行的性能优化,这是很常见的.在单线程应用程序中,也可能发生内存重新排序,但它对程序员来说是不可见的,就好像按程序顺序访问内存一样.对于SMP来说,内存障碍可以用来强制执行某种内存排序.

我不确定的是关于单处理器中的多线程.请考虑以下示例:当线程1运行时,商店f可以在商店之前发生x.假设在f写入之后以及之前x写入上下文切换.现在线程2开始运行,它结束循环并打印0,这当然是不可取的.

// Both x, f are initialized w/ 0.
// Thread 1
x = 42;
f = 1;

// Thread 2
while (f == 0)
  ;
print x;
Run Code Online (Sandbox Code Playgroud)

上述情况可能吗?或者是否保证在线程上下文切换期间提交物理内存?

根据这个维基,

当程序在单CPU机器上运行时,硬件执行必要的簿记,以确保程序执行就好像所有内存操作都按程序员指定的顺序执行(程序顺序),因此不需要内存屏障.

虽然它没有明确提到单处理器多线程应用程序,但它包括这种情况.

我不确定它是否正确/完整.请注意,这可能高度依赖于硬件(弱/强内存模型).因此,您可能希望在答案中包含您知道的硬件.谢谢.

PS.设备I/O等不是我关心的问题.它是一个单核单处理器.

编辑:感谢Nitsan的提醒,我们假设这里没有编译器重新排序(只是硬件重新排序),并且线程2中的循环没有被优化掉.再次,魔鬼在细节中.

c++ multithreading memory-barriers

20
推荐指数
2
解决办法
1861
查看次数

我应该何时更喜欢非会员非朋友功能到会员功能?

Meyers在他的书"Effective C++"中提到,在某些情况下,非成员非朋友函数比成员函数更好地封装.

例:

// Web browser allows to clear something
class WebBrowser {
public:
  ...
  void clearCache();
  void clearHistory();
  void removeCookies();
  ...
};
Run Code Online (Sandbox Code Playgroud)

许多用户希望一起执行所有这些操作,因此WebBrowser也可能提供一个功能:

class WebBrowser {
public:
  ...
  void clearEverything();  // calls clearCache, clearHistory, removeCookies
  ...
};
Run Code Online (Sandbox Code Playgroud)

另一种方法是定义非成员非朋友函数.

void clearBrowser(WebBrowser& wb)
{
  wb.clearCache();
  wb.clearHistory();
  wb.removeCookies();
}
Run Code Online (Sandbox Code Playgroud)

非成员函数更好,因为"它不会增加可以访问类的私有部分的函数的数量.",从而导致更好的封装.

喜欢的功能clearBrowser方便的功能,因为他们不能提供任何功能的WebBrowser一些其他方式的客户端无法获得已.例如,如果clearBrowser不存在,客户可以只打电话clearCache,clearHistoryremoveCookies他们自己.

对我而言,便利功能的例子是合理的.但是当非会员版本擅长时,除了便利功能之外还有其他例子吗?

更一般地说,什么时候使用哪些规则

c++ encapsulation

17
推荐指数
1
解决办法
2449
查看次数

为什么只有在堆分配的情况下才允许零长度数组?

我注意到不允许创建零堆长度的非堆分配数组.

// error: cannot allocate an array of constant length zero
char a[0];
Run Code Online (Sandbox Code Playgroud)

我还注意到它允许创建零长度的堆分配数组.

// this is okay though
char *pa = new char[0];
Run Code Online (Sandbox Code Playgroud)

我猜他们都是标准保证(我手头没有标准副本).如果是这样,为什么他们如此不同?为什么不在堆栈上允许零长度数组(反之亦然)?

c++ arrays

15
推荐指数
2
解决办法
3255
查看次数

编译器如何知道物理地址的对齐?

我知道有些CPU架构不支持未对齐的地址访问(例如,ARM 4之前的ARM架构没有访问内存中半字对象的指令).并且该架构的某些编译器(例如,某些版本的GCC)在找到未对齐的地址时将使用一系列内存访问,因此未对齐的访问对开发人员来说几乎是透明的.(请参阅GCC的权威指南,William冯哈根)

但我想知道编译器如何知道地址是否对齐?毕竟,编译器看到的是虚拟地址(有效地址,EA),如果它可以看到任何东西.程序运行时,EA可以通过OS映射到任何物理地址.即使虚拟地址对齐,生成的物理地址也可能未对齐,不是吗?物理地址的对齐是真正重要的,并在CPU地址线上传输.

因为编译器根本不知道物理地址,所以如何知道变量的地址是否对齐?

c++ compiler-construction alignment

11
推荐指数
1
解决办法
740
查看次数

何时以及为什么基类中的析构函数不能被定义为虚拟?

下面的示例说明了如何防止复制派生类.它基于一个基类,其中声明了复制构造函数和复制赋值运算符private.

class Uncopyable
{
protected:
   // allow construction and destruction of derived objects...
   Uncopyable() {}
   ~Uncopyable() {}

private:
   // but prevent copying...
   Uncopyable(const Uncopyable&);
   Uncopyable& operator=(const Uncopyable&);
};
Run Code Online (Sandbox Code Playgroud)

我们可以使用这个类,结合私有继承,使类不可复制:

class derived: private Uncopyable
{...};
Run Code Online (Sandbox Code Playgroud)

请注意,类中的析构函数Uncopyable未声明为virtual.

以前,我了解到了

  • 基类中的析构函数应该是virtual.
  • 不应该在非基类中创建析构函数virtual.

在这个例子中,析构函数Uncopyable不是virtual,但它是继承的.这似乎违背了我之前学到的智慧.

何时以及为什么基类中的析构函数不能被定义为virtual

c++ virtual-destructor

10
推荐指数
1
解决办法
794
查看次数