std::atomic删除了复制赋值运算符。因此,以下结果会导致编译器错误:
std::atomic<int> a1, a2;
a1 = a2; // Error
Run Code Online (Sandbox Code Playgroud)
我认为删除运算符的动机已在这篇文章中进行了解释。到目前为止,一切都很好。但我注意到,添加volatile会导致代码突然编译(在godbolt上运行):
volatile std::atomic<int> a1, a2;
a1 = a2; // OK
Run Code Online (Sandbox Code Playgroud)
我的项目并不真正需要volatile变量,所以这只是出于好奇:这是 C++ 标准中的疏忽,还是故意的(为什么?)?
注意:我可以通过修改定义来得到编译器错误std::atomic,或者通过添加
atomic & operator=(const volatile atomic &) volatile = delete;
Run Code Online (Sandbox Code Playgroud)
或者通过删除转换运算符 operator T() const volatile noexcept。
考虑以下代码:
struct Temp{ int i = 0; };
Temp GetTemp() { return Temp{}; }
int main()
{
for (struct{Temp const & t; int counter;} v = {GetTemp(), 0};
v.counter < 10;
++v.counter)
{
// Is v.t guaranteed to not be a dangling reference?
std::cout << v.t.i << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
因此GetTemp()返回一个临时对象,然后将其分配给常量引用变量。但是,该常量引用变量是匿名本地结构的成员。问题:C++ 标准是否保证该临时对象的生命周期延长到循环终止之后?
考虑到这个问题,我预计答案是否定的,即我在循环体中得到了一个悬空引用。然而, gcc 和 clang 似乎延长了生命周期(参见godbolt 上的示例),甚至不抱怨-fsanitize=undefined,这让我感到惊讶。
我在C++中进行了一些科学计算,并尝试利用OpenMP来实现某些循环的并行化.到目前为止,这种方法运行良好,例如在具有8个线程的Intel i7-4770上.
我们在一个主板上有一个小型工作站,由两个Intel CPU(E5-2680v2)组成.代码可以工作,只要它在1个CPU上运行,并且拥有尽可能多的线程.但是一旦我使用第二个CPU,我会不时观察到不正确的结果(大约每50到100次运行代码).即使我只使用2个线程并将它们分配给两个不同的CPU,也会发生这种情况.由于我们有5个这样的工作站(都是相同的),我在每个工作站上运行代码,并且都显示了这个问题.
该工作站在OpenSuse 13.1,内核3.11.10-7上运行.问题存在于g ++ 4.8.1和4.9.0,以及英特尔的icc 13.1.3.192(尽管问题不会经常发生在icc上,但它仍然存在).
症状可描述如下:
std::complex<double>* mFourierValues;mFourierValues[idx] = newValue;mFourierValues[idx] == newValue,这种检查会不时失败(尽管不是每次结果都不正确).所以症状看起来像是在没有任何同步的情况下同时访问元素.但是,当我将索引存储在std::vector(使用适当的#pragma omp critical)时,所有指标都是唯一的并且在正确的范围内.
经过几天的调试,我的怀疑越来越多,其他事情正在发生,我的代码是正确的.对我来说,当CPU将缓存与主内存同步时,看起来很奇怪.
因此,我的问题是:
[编辑:删除旧代码,见下文]
好的,我终于能够生成一个更短(和自我一致)的代码示例.
complex<double> mAllElements[tensorIdx][kappa1][kappa2][kappa3].即我有3个Rank-3-tensors(tensorIdx).每个张量代表一个三维数组,索引为kappa1,kappa2和kappa3.kappa1循环是被并行化的循环(并且是最外层的循环).它们位于DoComputation().main(),我打电话DoComputation()一次得到一些参考值,然后我多次调用它并比较结果.它们应该完全匹配,但有时它们不匹配.不幸的是,代码仍然长约190行.我试图进一步简化它(只有1张等级1,等等),但后来我再也无法重现这个问题了.我想这是因为内存访问是非对齐的(循环tensorIdx是最里面的)(我知道,这远非最优.)
此外,在适当的地方需要一些延迟,以重现错误.这就是nops()电话的原因.没有它们,代码运行得更快,但到目前为止还没有显示出问题.
请注意,我CalcElementIdx() …
我偶然发现了下面的代码。该"DerivedFoo"案例在 MSVC 上产生的结果与在 clang 或 gcc 上产生的结果不同。即,clang 13 和 gcc 11.2 调用复制构造函数,Foo而 MSVC v19.29 调用模板化构造函数。我正在使用 C++17。
考虑到所有编译器都同意调用模板化构造函数的非派生情况("Foo"),我认为这是 clang 和 gcc 中的错误,而 MSVC 是正确的吗?或者我解释错误而 clang/gcc 是正确的?任何人都可以阐明可能发生的事情吗?
代码(https://godbolt.org/z/bbjasrraj):
#include <iostream>
using namespace std;
struct Foo {
Foo() {
cout << "\tFoo default constructor\n";
}
Foo(Foo const &) { cout << "\tFoo COPY constructor\n";
}
Foo(Foo &&) {
cout << "\tFoo move constructor\n";
}
template <class U>
Foo(U &&) {
cout << "\tFoo TEMPLATED constructor\n"; …Run Code Online (Sandbox Code Playgroud) 我正在努力解决自定义分配器的性能问题。我的问题是关于调试版本。
通常情况下,如果只有一点点下降我并不介意。但目前我正在以 4fps 播放某些内容,而如果没有自定义分配器,则播放速度为 60fps(并且可能会更快)。这使得软件开发变得更加困难。
我一直把它确定下来......基本上继承了标准分配器
请参阅“quick-bench.com”的以下结果 https://quick-bench.com/q/ep3uyYNK6rh_6f8AGAP0zIAflAA
蓝色条很简单:
int main() {
std::vector<uint8_t, std::vector<uint8_t>::allocator_type> buffer;
buffer.reserve(numBytes);
buffer.resize(numBytes);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
黄色条:
template<typename T>
class CustomAllocatorType : public std::vector<uint8_t>::allocator_type {};
int main() {
std::vector<uint8_t, CustomAllocatorType<uint8_t>> buffer;
buffer.reserve(numBytes);
buffer.resize(numBytes);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
用以下内容封装自定义分配器:
#pragma GCC push_options
#pragma GCC optimize ("-O3")
// ....
#pragma GCC pop_options
Run Code Online (Sandbox Code Playgroud)
没有任何效果。我想我需要对向量实例本身执行此操作,但我不想走那么远......
有谁知道这个问题的解决方案?
考虑以下代码:
struct Foo{
std::string s1;
std::string s2;
};
int main(){
Foo f{.s1 = "s1", .s2 = f.s1 + "s2"};
std::cout << "s1='" << f.s1 << "', s2='" << f.s2 << "'" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
特别注意 的初始化访问:s2的第一个成员。最新的 clang、gcc 和 MSVC 对代码很满意,并给出了天真的预期结果(它们打印)。观看Godbolt直播。f.s2 = f.s1 + "s2""s1='s1', s2='s1s2'"
问题:这合法吗?换句话说,标准是否保证在f.s1指定的初始化器被.s2评估之前被初始化?
相关:有一个类似的问题询问是否.s2 = .s1 + "s2"合法,这显然是不合法的,因为它无法编译。另外,P0328(根据此答案)可能相关,但我看不到我的问题在那里得到解答。
c++ designated-initializer language-lawyer aggregate-initialization c++20
在对涉及 的代码进行基准测试时std::optional<double>,我注意到 MSVC 生成的代码的运行速度大约是 clang 或 gcc 生成的代码的一半。在花了一些时间减少代码后,我注意到 MSVC 显然在为std::optional::operator=. 使用std::optional::emplace()不会表现出速度减慢。
以下功能
void test_assign(std::optional<double> & f){
f = std::optional{42.0};
}
Run Code Online (Sandbox Code Playgroud)
产生
sub rsp, 24
vmovsd xmm0, QWORD PTR __real@4045000000000000
mov BYTE PTR $T1[rsp+8], 1
vmovups xmm1, XMMWORD PTR $T1[rsp]
vmovsd xmm1, xmm1, xmm0
vmovups XMMWORD PTR [rcx], xmm1
add rsp, 24
ret 0
Run Code Online (Sandbox Code Playgroud)
注意未对齐的 mov 操作。相反,函数
void test_emplace(std::optional<double> & f){
f.emplace(42.0);
}
Run Code Online (Sandbox Code Playgroud)
编译为
mov rax, 4631107791820423168 ; 4045000000000000H
mov BYTE PTR [rcx+8], 1
mov …Run Code Online (Sandbox Code Playgroud) OpenMP标准(<= 4.0)说atomic:
#pragma omp atomic [read | write | update | capture ] new-line
expression-stmtwhere
expression-stmt是具有以下形式之一的表达式语句:
...
If子句是更新还是不存在:
x++;
...
在前面的表达式中:
x和v(如果适用)都是具有标量类型的l值表达式.
...
因此,当我正确解释这一点时,以下短代码片段是非法的:
int main()
{
int myCounter = 0;
int& reference = myCounter;
#pragma omp parallel for
for (int i = 0; i < 100; ++i)
{
#pragma omp atomic
reference++; // Increment through reference.
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
原因:根据这篇文章,引用(这里int& reference)不是标量类型.但是标准明确规定它必须是一个,才能使用atomic.
代码用g ++编译,没有任何警告( …
我有以下代码:
struct B
{
B(int) {}
};
template <typename T>
class Base : public B
{
friend T;
Base() : B(1) {}
};
class Derived : public Base<Derived>
{
public:
void do_sth() const {}
};
int main()
{
auto x = Derived{}; //Compiles only when using C++11
auto x1 = Derived(); //Compiles using C++17/20 flag
x.do_sth();
x1.do_sth();
}
Run Code Online (Sandbox Code Playgroud)
由于某种原因,当使用 C++17 时,由于“x”变量的“不可编译”初始化,编译失败。编译器说:
Base::Base() [with T = Derived]' 在此上下文中是私有的
但正如您所看到的,下面我创建了一个相同类型的对象,但这次我没有使用统一初始化。x1 变量可以使用 C++11 或 C++17 标准进行编译,但 'x' 变量只能在 C++11 模式下编译。这是为什么?标准发生了什么变化导致了这个问题?
我从[https://www.scs.stanford.edu/~dm/blog/va-opt.html]获得了这个源代码。将 MSVC 与 C++20 一起使用它无法编译,但可以在其他编译器上编译。为什么?我该如何解决这个问题?
`/* compile with:
c++ -std=c++20 -Wall -Werror make_enum.cc -o make_enum
*/
#include <iostream>
#define PARENS ()
// Rescan macro tokens 256 times
#define EXPAND(arg) EXPAND1(EXPAND1(EXPAND1(EXPAND1(arg))))
#define EXPAND1(arg) EXPAND2(EXPAND2(EXPAND2(EXPAND2(arg))))
#define EXPAND2(arg) EXPAND3(EXPAND3(EXPAND3(EXPAND3(arg))))
#define EXPAND3(arg) EXPAND4(EXPAND4(EXPAND4(EXPAND4(arg))))
#define EXPAND4(arg) arg
#define FOR_EACH(macro, ...) \
__VA_OPT__(EXPAND(FOR_EACH_HELPER(macro, __VA_ARGS__)))
#define FOR_EACH_HELPER(macro, a1, ...) \
macro(a1) \
__VA_OPT__(FOR_EACH_AGAIN PARENS (macro, __VA_ARGS__))
#define FOR_EACH_AGAIN() FOR_EACH_HELPER
#define ENUM_CASE(name) case name: return #name;
#define MAKE_ENUM(type, ...) \
enum type { \
__VA_ARGS__ \
}; \ …Run Code Online (Sandbox Code Playgroud) 考虑以下相等运算符的实现,用 C++20 编译(在godbolt上运行):
#include <optional>
template <class T>
struct MyOptional{
bool has_value() const { return false;}
T const & operator*() const { return t; }
T t{};
};
template <class T>
bool operator==(MyOptional<T> const & lhs, std::nullopt_t)
{
return !lhs.has_value();
}
template <class U, class T>
bool operator==(U const & lhs, MyOptional<T> const & rhs)
{
// gcc error: no match for 'operator==' (operand types are 'const std::nullopt_t' and 'const int')
return rhs.has_value() ? lhs == *rhs : …Run Code Online (Sandbox Code Playgroud)