小编Wak*_*zil的帖子

需要帮助理解从B.Stroustrup的新书中提取的本文

41.2.1 Memory Location他的新书中,B.Stroustrup写了以下内容:

考虑两个全局变量bc:

// thread1
char c = 0;
void f()
{
   c = 1;
   int x = c;
} 

// thread2
char b = 0;
void g()
{
   b = 1;
   int y = b;
}
Run Code Online (Sandbox Code Playgroud)

现在,x == 1和y == 1,正如任何人所期望的那样.为什么这甚至值得说?考虑如果链接器在内存中的同一个字中分配cb并且(像大多数现代硬件一样)机器无法加载或存储小于单词的任何内容,可能会发生 什么:

在此输入图像描述

如果没有定义明确且合理的内存模型,线程1可能会读取包含bc的单词,更改c,并将单词写回内存.同时线程2可以用b做同样的事情.然后,无论哪个线程设法首先读取该单词,哪个线程设法将其结果写回内存最后将确定结果.我们可能会得到10,01,或11 (而不是00).记忆模型使我们免于混乱; 我们得到 11.00不能发生的原因是在任一线程启动之前(由编译器或链接器)完成bc的初始化. …

c++ memory multithreading c++11

5
推荐指数
1
解决办法
202
查看次数

我的解释是否正确n3797 8.5.3/5?

n3797中第8.5.3/5段:

对类型"cv1 T1"的引用由类型"cv2 T2"的表达式初始化,如下所示:

  • 如果引用是左值引用和初始化表达式

    • 是左值(但不是位域),"cv1 T1"与"cv2 T2"引用兼容,或者

    • 具有类类型(即,T2是类类型),其中T1与T2不是引用相关的,并且可以转换为类型为"cv3 T3"的左值,其中"cv1 T1"与"cv3"引用兼容T3"(通过枚举适用的转换函数(13.3.1.6)并通过重载决策(13.3)选择最佳转换函数来选择此转换),

...

英语不是我的母语,但在我看来,粗体这个短语(我的重点)给出了T1可以转换为cv3 T3类型左值的想法,我认为这是不正确的.根据我的理解,T2是必须转换为cv3 T3的类型,例如:

struct B : A { operator int&(); } b;    
int& ir = B();
Run Code Online (Sandbox Code Playgroud)

显示.

c++ reference language-lawyer c++11 c++14

5
推荐指数
1
解决办法
360
查看次数

我对下面的断言是对的吗?

在他的新书"TCPL"的第10.4.3节中,B.Stroustrup写道:

可以在常量表达式中使用足够简单的用户定义类型.例如:

struct Point {
    int x,y,z;
    constexpr Point up(int d) { return {x,y,z+d}; }
    constexpr Point move(int dx, int dy) { return {x+dx,y+dy}; }
// ...
};
Run Code Online (Sandbox Code Playgroud)

具有constexpr构造函数的类称为文字类型.为了简单到constexpr,构造函数必须有一个空体,所有成员必须由可能的常量表达式初始化.例如:

constexpr Point origo {0,0};

由于以下原因,这似乎让我感到困惑:

  • struct Point 没有用户定义的构造函数,它的隐式默认构造函数也不是constexpr.
  • constexpr Point origo {0,0};由于标准(N3337)第7.1.5/9段关于使用constexpr对象声明和第8.5.1/7段有关汇总初始化的汇编而编制.它与constexpr构造函数无关.

c++ initialization constexpr c++11

5
推荐指数
1
解决办法
238
查看次数

为什么不透明枚举声明不是定义?

第3.1 / 2节说,不透明枚举声明是不是定义的声明。但是,它占用内存空间。将其与也具有大小的类定义进行比较。两者都是标准的完整类型。为什么一个是声明,另一个是定义?

#include <iostream>
enum A : int;   // opaque-enum-declaration
class B{};      // a class definition

int main() {
    std::cout << sizeof(A) << '\n';
    std::cout << sizeof(B) << '\n';
}
Run Code Online (Sandbox Code Playgroud)

输出量

4

1个

编辑

enum A : int;据我所知,下面的不透明枚举声明已定义。

#include <iostream>
enum A : int;   // opaque-enum-declaration

int main() {
    A a;
    std::cout << a << '\n';
}
Run Code Online (Sandbox Code Playgroud)

编辑1

就变量a而言,先前的代码段与下面的代码段没有区别。它们都使变量未定义。因此,很难接受那enum : int;是一个声明和enum A : int {quick, brown, fox}; …

c++ language-lawyer c++11

5
推荐指数
1
解决办法
1514
查看次数

编译器如何在下面的代码中通过ADL找到模板函数X :: max(T const&,T const&)?

该标准的引用表示赞赏.

#include <iostream>

namespace X {
    class A {};
}

template <typename T>
inline T const& max(T const& a, T const& b, T const& c)
{
    return max(max(a, b), c);
}

inline X::A const& max(X::A const& a, X::A const& b)
{
    std::cout << "non-template" << '\n';
    return a;
}

int main()
{
    X::A a, b, c;
    max(a, b, c);
}

namespace X {
    template <typename T>
    inline T const& max(T const& a, T const& b)
    {
        std::cout << "template" << …
Run Code Online (Sandbox Code Playgroud)

c++ templates language-lawyer argument-dependent-lookup c++11

5
推荐指数
1
解决办法
440
查看次数

如何初始化良好的初始化?

[class.conv.ctor]/2中的示例包含以下初始化:

Z a3 = Z(1);    // OK: direct initialization syntax used
Run Code Online (Sandbox Code Playgroud)

这怎么被认为是直接初始化语法?

c++ initialization language-lawyer c++17

5
推荐指数
1
解决办法
235
查看次数

为什么即使允许copy-elision发生,代码也需要具有可访问的复制/移动构造函数?

Nicol Bolas 在SO的回答中写道:

在许多情况下允许复制省略.但是,即使允许,代码仍然必须能够工作,好像副本没有被删除.也就是说,必须有一个可访问的副本和/或移动构造函数.]

为什么有必要(在"保证副本省略"出现之前)代码维护复制/移动构造函数,即使允许复制省略发生?

为什么" 保证复制省略 "使程序员免于这些要求?

c++ language-lawyer copy-elision c++14

5
推荐指数
1
解决办法
183
查看次数

在C++ 11标准中,它表示char*p ="abc"; 是不是形成了?

C++ 11标准中的哪个地方说它char* p = "abc";是不正确的?

c++ standards c++11

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

在下面的示例中,函数对象"rev"是根据其自身定义的.这怎么可能?

这个例子(void function f(string& s1, string& s2))取自B.Stroustup新书"TCPL"第4版的第297/298页.

#include <iostream>
#include <functional>
#include <string>
#include <algorithm>

void f(std::string& s1, std::string& s2)
{
    std::function<void(char* b, char* e)> rev =
                [&](char* b, char* e) { if (1<e-b) { std::swap(*b,*--e); rev(++b,e); } };
    rev(&s1[0],&s1[0]+s1.size());
    rev(&s2[0],&s2[0]+s2.size());
}

int main()
{
    std::string s1("Hello");
    std::string s2("World");
    f(s1, s2);
    std::cout << s1 << " " << s2 << '\n';
}
Run Code Online (Sandbox Code Playgroud)

代码编译并打印出正确的结果,即函数f反转输入字符串的字符.节目输出:

olleH dlroW

我可以理解下面表达式的语义.我的问题是接受它的语法,因为变量rev是根据它自己定义的.

std::function<void(char* b, char* e)> rev =
                    [&](char* b, char* …
Run Code Online (Sandbox Code Playgroud)

c++ lambda functor c++11

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

标准中的哪个部分说成员别名声明可以像使用静态成员一样使用?

请考虑以下代码段:

#include <iostream>
struct A { int i; using Int = int; };

int main()
{
    std::cout << sizeof(A::Int) << '\n';
}
Run Code Online (Sandbox Code Playgroud)

它在clang和GCC中正常编译和执行.我知道这看起来很明显,但我在标准(C++ 14)中找不到任何支持引用A::Int的内容main().

c++ alias language-lawyer c++14

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