小编JMC*_*JMC的帖子

双括号"[[foo()]]类型名称的含义;" c ++中的语法?

文章如何避免错误共享,剪断对准下面的代码是提出:

// C++ (using C++0x alignment syntax)
template<typename T>
struct cache_line_storage {
   [[ align(CACHE_LINE_SIZE) ]] T data;
   char pad[ CACHE_LINE_SIZE > sizeof(T)
        ? CACHE_LINE_SIZE - sizeof(T)
        : 1 ];
};
Run Code Online (Sandbox Code Playgroud)

第4行是什么意思?我以前从未见过这种双括号语法.

c++ syntax brackets

24
推荐指数
1
解决办法
1673
查看次数

由 if (false) 保护的数据竞争...标准是怎么说的?

考虑以下情况

// Global
int x = 0; // not atomic

// Thread 1
x = 1;

// Thread 2
if (false)
    x = 2;
Run Code Online (Sandbox Code Playgroud)

根据标准,这是否构成数据竞争?[intro.races] 说:

如果两个表达式求值之一修改内存位置 (4.4),而另一个表达式求值读取或修改同一内存位置,则两个表达式求值会发生冲突。

如果程序的执行包含两个潜在并发冲突的操作,并且至少其中一个操作不是原子操作,并且两者都发生在另一个操作之前,则该程序的执行将包含数据争用,除了下面描述的信号处理程序的特殊情况之外。任何此类数据竞争都会导致未定义的行为。

从语言律师的角度来看是否安全,因为程序永远不能执行“表达式求值” x = 2;

从技术角度来看,如果某个奇怪、愚蠢的编译器决定对该写入执行推测执行,并在检查实际情况后将其回滚,该怎么办?

激发这个问题的原因是(至少在标准 11 中),允许以下程序的结果完全取决于重新排序/推测执行:

// Thread 1:
r1 = y.load(std::memory_order_relaxed);
if (r1 == 42) x.store(r1, std::memory_order_relaxed);
// Thread 2:
r2 = x.load(std::memory_order_relaxed);
if (r2 == 42) y.store(42, std::memory_order_relaxed);
// This is allowed to result in r1==r2==42 in c++11
Run Code Online (Sandbox Code Playgroud)

(比较https://en.cppreference.com/w/cpp/atomic/memory_order

c++ concurrency memory-model language-lawyer

18
推荐指数
2
解决办法
1275
查看次数

C++20“透明可替换”关系

在 C++20 的最终工作草案(以及下面链接的最新公开可用草案)中,关于如何允许对象替换其他对象,[basic.life] 的措辞已经改变,以便指针、引用和对象的name 自动引用新对象。为此,引入了“透明可替换”的关系。但是,我不确定我是否正确理解了这一点。考虑这个例子:

struct X {int a = 3; float b;};
X x;
new(&x.a) int(5);
x.a == 5 // true without std::launder?
Run Code Online (Sandbox Code Playgroud)

在 C++17 中这当然是正确的,因为旧的 int 既不是 const 对象,也不是具有 const 非静态成员的类。

然而,现在新的透明可替换关系可能不再允许这样做了。在考虑新旧 int 对象的关系时,满足条件(8.1)到(8.4),但条件(8.5)呢?

o1 (旧的 int)和 o2 (新的 int)都是完整的对象(旧的 int 肯定是一个子对象,所以这部分是假的)或者 o1 和 o2 分别是对象 p1 和 p2 的直接子对象,而 p1可以透明地替换为 p2。

new int 是一个完整的对象,因为它是“自己”构造的(我们只放置了一个 new int 而不是一个新的 X)?

或者是否可以认为由于[intro.object]\2的措辞,新 int 是 x 的子对象,就像旧 int 一样,(我高度怀疑这是预期的解释,tbh),因此 x 满足p1 和 p2 …

c++ language-lawyer c++20

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

你能通过 char* 访问任何对象的对象表示吗?

我偶然发现了一个reddit 线程,用户在其中发现了 C++ 标准的一个有趣细节。该线程没有产生太多建设性的讨论,因此我将在这里复述我对问题的理解:

  • OP 希望以memcpy符合标准的方式重新实现
  • 他们试图通过 using 来做到reinterpret_cast<char*>(&foo)这一点,这是严格别名限制的允许例外,其中允许重新解释 aschar访问对象的“对象表示”。
  • [expr.reinterpret.cast]说这样做会导致static_­cast<cv T*>(static_­cast<cv void*>(v)),所以reinterpret_cast在这种情况下等价于 static_cast'ing first tovoid *然后 to char *
  • [expr.static.cast]结合[basic.compound]

“指向 cv1 void 的指针”类型的纯右值可以转换为“指向 cv2 T 的指针”类型的纯右值,其中 T 是对象类型,而 cv2 与 cv1 具有相同的 cv 限定,或比 cv1 更高的 cv 限定。[...]如果原始指针值指向对象 a,并且存在 T 类型的对象 b(忽略 cv 限定)与 a 的指针可相互转换,则结果是指向 b 的指针。[...] [强调我的]

现在考虑以下联合类:

union Foo{
    char c;
    int i;
}; …
Run Code Online (Sandbox Code Playgroud)

c++ strict-aliasing language-lawyer

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

不同编译器的重载分辨率不同

我已经构建了我的问题的以下最小示例:

#include <iostream>

struct Foo {
  Foo() {
    std::cout << "default" << std::endl;
  }
  Foo(Foo& f2) {
    std::cout << "non-const" << std::endl;
  }
  Foo(const Foo& f2) {
    std::cout << "const" << std::endl;
  }
};

int main() {
        std::pair<Foo, int> foop0(Foo(), 1);
        std::cout << std::endl;
        std::pair<const Foo, int>foop1(foop0);
}
Run Code Online (Sandbox Code Playgroud)

在我的 Ubuntu 机器上 g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 将打印出以下内容:

$ g++ -std=c++14 test.cpp -o test && ./test
default
const

const
Run Code Online (Sandbox Code Playgroud)

但是,我的 Mac 上的 Apple clang(版本 11.0.3 (clang-1103.0.32.62) Target: x86_64-apple-darwin19.4.0)将打印:

$ g++ -std=c++14 test.cpp …
Run Code Online (Sandbox Code Playgroud)

c++ compilation overload-resolution

8
推荐指数
1
解决办法
82
查看次数

UB when deleting storage-providing char array from free store?

The following example of usage of placement-new was provided by an earlier version of the cppreference page:

char* ptr = new char[sizeof(T)]; // allocate memory
T* tptr = new(ptr) T;            // construct in allocated storage ("place")
tptr->~T();                      // destruct
delete[] ptr;                    // deallocate memory
Run Code Online (Sandbox Code Playgroud)

Inspired by this comment on an older SO thread I have come to the conclusion that this might be UB. However, in the talk page of that cppreference article there is a small discussion as …

c++ placement-new undefined-behavior language-lawyer

8
推荐指数
0
解决办法
101
查看次数

6
推荐指数
1
解决办法
6608
查看次数

为什么 swift 不警告这个不可发送的全局传递到不同的任务?

考虑以下代码:

class Cat {
    var name = "Tom"
}

class Globals {
    var cat = Cat()
}

let glob = Globals()

func one () {
    Task {glob.cat.name="Max"} // Expected Warning about some nonSendable moving into a different concurrency domain
}
Run Code Online (Sandbox Code Playgroud)

通常,-warn-concurrency启用后,Swift/Xcode 会警告不可发送的内容跨并发域。

根据我的理解,传递给的闭包Task必须始终是一个@Sendable闭包。闭包@Sendable只能捕获 Sendables。但是,Globals 不是可发送类型。我预计会出现类似以下的警告

@Sendable在闭包中捕获具有不可发送类型“Globals”的“glob”

不会发出此类警告。

swift swift-concurrency

6
推荐指数
0
解决办法
292
查看次数

分配器的分配和构造是否通过 [basic.life]p8 明确定义?

cppreference 的 std::allocator 示例包含以下代码(为简单起见缩短):

// default allocator for ints
std::allocator<int> alloc1;

using traits_t1 = std::allocator_traits<decltype(alloc1)>; // The matching trait
p1 = traits_t1::allocate(alloc1, 1);
traits_t1::construct(alloc1, p1, 7);  // construct the int
std::cout << *p1 << '\n';
Run Code Online (Sandbox Code Playgroud)

就分配器而言,相当简单。然而,标准保证中的哪些措辞p1实际上指向新对象呢?

根据std::allocate和[allocator.members]上的 cppreference 文档,默认分配器的函数allocate()

在存储中创建 T[n] 类型的数组并开始其生存期,但不开始其任何元素的生存期。

并返回

[指针] 指向 n 个 T 类型对象的数组的第一个元素,该数组的元素尚未构造。

Afaik,数组创建措辞已添加到标准中,以便指针上的指针算术有效。无论如何,这意味着返回的指针指向 的第一个元素,T[]并且该第一个元素的生命周期尚未开始

construct()然后在此位置创建一个对象,但是,它不会返回指向该对象的指针。我们拥有的唯一指针仍然是返回的指针allocate

通常,当一个对象被放置在过期对象的位置时,它可以在[basic.life]p8中规定的条件下“透明地替换”旧对象:(强调我的)

如果在一个对象的生命周期结束之后,在该对象所占用的存储被重用或释放之前,在原对象所占用的存储位置上创建了一个新对象,一个指向原对象的指针[... ] 将自动引用新对象,并且一旦新对象的生命周期开始[...]

该数组元素的生命周期从未开始,因此它不可能结束,因此这不适用。那么如何才能保证对新构造的对象的访问是明确定义的呢?每次通话后都std::launder应该使用吗construct …

c++ memory-management allocator language-lawyer

6
推荐指数
1
解决办法
87
查看次数

为什么是&amp;mut发送?线程如何在安全的 Rust 中捕获 &amp;mut?

语言文档指出:

&mut TSend当且仅当TSend

有人可以提供一个代码示例来说明这实际上是相关的吗? thread::spawn要求其闭包在生命周期内借用'static,因此线程闭包只能借用静态变量,但安全 Rust 不允许static mut。因此,无论如何都不应该捕获线程闭包中的任何内容&mut

&muta的能力在哪些用例中Send具有相关性?

multithreading thread-safety rust

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

仅在使用 &amp;mut 或线程时“借用的数据在闭包之外转义”?

当尝试将引用重新分配到闭包内部其他位置时,我注意到一个我无法解释的奇怪行为,如以下最小示例所示:

fn main() {
    let mut foo: i32 = 5;
    let mut foo2: i32 = 6;
    let mut borrower = &mut foo; // compiles OK without mut here and below
    let mut c = || {
        borrower = &mut foo2;    // compiles OK without mut here and above
    };
}
Run Code Online (Sandbox Code Playgroud)

仅当引用为:时才会产生以下错误&mut

error[E0521]: borrowed data escapes outside of closure
  --> src/main.rs:25:9
   |
23 |     let mut borrower = &mut foo;
   |         ------------ `borrower` declared here, outside of the closure …
Run Code Online (Sandbox Code Playgroud)

closures rust borrow-checker

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

为什么我可以使用 &amp;mut (**ref) 创建两个实时 &amp;mut 到同一个变量?

考虑以下两个代码片段:

fn main() {
    let mut foo = 1;
    let mut borrower = &mut foo;
    
    let mut borrower2 = &mut foo;  // error: cannot borrow `foo` as mutable more than once at a time

    *borrower2 = 2;
    *borrower = 3;

    println!("{}", foo);
}
Run Code Online (Sandbox Code Playgroud)

这不会像预期的那样编译,因为不能对同一变量有两个可变引用。但是,如果我按如下所示替换有问题的行,它就会起作用:

fn main() {
    let mut foo = 1;
    let mut borrower = &mut foo;
    
    let rr = &mut borrower;
    let borrower2 = &mut (**rr);
    
    *borrower2 = 2; // I can use both of these to mutate …
Run Code Online (Sandbox Code Playgroud)

rust borrow-checker

2
推荐指数
1
解决办法
155
查看次数