我正在编写一些必须处理 NTP 时间的代码。我决定用 来代表他们std::chrono::duration,我希望这能让我的时间数学更容易做。
NTP 时间由无符号 64 位整数表示,高 32 位为自纪元以来的秒数,低 32 位为小数秒。纪元日期是 1900 年 1 月 1 日,但这与我在这里处理的问题是一个单独的问题,而且我已经知道如何处理这个问题。对于我正在使用的示例,为了使数学更简单,假设纪元为 1970 年 1 月 1 日。
持续时间的表示很简单:std::chrono::duration<std::uint64_t, std::ratio<1, INTMAX_C(0x100000000)>>。问题在于当我尝试在 NTP 时间和系统时钟之间进行转换时。
在我的系统上,std::chrono::system_clock::duration是std::chrono::duration<int64_t, std::nano>. 当我尝试std::chrono::duration_cast在这两个持续时间之间进行转换时,我在任一方向上都得到了大量的截断。在调试器中跟踪这一点,我发现它与实现有关duration_cast,在 libstdc++、libc++ 和 boost::chrono 中以同样的方式失败。简而言之,要从系统表示转换为 ntp 表示,它乘以比率 8388608/1953125,并在另一个方向上乘以相反的比率。它首先乘以分子,然后除以分母。数学是正确的,但初始乘法溢出了 64 位表示并被截断,尽管实际转换(除法后)仍然可以轻松地用这些位表示。
我可以手动进行此转换,但我的问题如下:
to_sys和from_sys功能的 NTP 时钟,我是否可以简单地使用std::chrono::clock_cast而不必担心其他微妙的问题?这是我用来测试这个的代码和一些示例输出:
// #define BOOST
#ifdef BOOST
# include <boost/chrono.hpp>
# define …Run Code Online (Sandbox Code Playgroud) 如何称呼new带有对齐方式的运算符?
auto foo = new(std::align_val_t(32)) Foo; //?
Run Code Online (Sandbox Code Playgroud)
然后,如何正确删除它?
delete(std::align_val_t(32), foo); //?
Run Code Online (Sandbox Code Playgroud)
如果这是使用这些重载的正确形式,那么为什么要抱怨抱怨free()/ delete / delete []不匹配?
考虑这个最小的例子:
#include <filesystem>
#include <iostream>
int main()
{
std::cout << std::filesystem::current_path() << '\n';
}
Run Code Online (Sandbox Code Playgroud)
它在 GCC 9.2 中按预期工作,但 Clang 8.0.1 拒绝编译<filesystem>头文件(来自 GCC 9.2 的 libstdc++):
# clang++ 1.cpp -std=c++17
In file included from 1.cpp:1:
In file included from Z:\Lander\msys2\mingw64\include\c++\9.2.0\filesystem:37:
Z:\Lander\msys2\mingw64\include\c++\9.2.0\bits/fs_path.h:636:31: error: invalid use of incomplete
type 'std::filesystem::__cxx11::filesystem_error'
_GLIBCXX_THROW_OR_ABORT(filesystem_error(
^~~~~~~~~~~~~~~~~
Z:\Lander\msys2\mingw64\include\c++\9.2.0\x86_64-w64-mingw32\bits/c++config.h:177:49: note: expanded
from macro '_GLIBCXX_THROW_OR_ABORT'
# define _GLIBCXX_THROW_OR_ABORT(_EXC) (throw (_EXC))
^~~~
Z:\Lander\msys2\mingw64\include\c++\9.2.0\bits/fs_fwd.h:61:9: note: forward declaration of
'std::filesystem::__cxx11::filesystem_error'
class filesystem_error;
^
1 error generated.
Run Code Online (Sandbox Code Playgroud)
它是 Clang 错误还是 libstdc++ 错误? …
I'm learning stateful template metaprogramming.
I've stumbled upon this example, which I've slightly modified.
#include <iostream>
namespace impl
{
template <typename T>
struct tag
{
friend auto get(tag);
};
template <typename T, auto V>
struct set
{
friend auto get(tag<int>) // <-- Originally it was `tag<T>`.
{
return V;
}
};
}
impl::set<int, 42> x;
int main()
{
std::cout << get(impl::tag<int>{});
}
Run Code Online (Sandbox Code Playgroud)
For some reason, it works on GCC, but not on Clang.
I don't see anything wrong with the …
我正在完成作业(因此我无法发布代码),并且很少出现此运行时错误:
*检测到堆栈粉碎*:终止中止(核心转储)
当我再次运行可执行文件后,一切正常。是否有原因导致此错误仅有时出现?作为参考,我试图完成的作业要求我们将文件中的数据加载到两个向量中,并对数据进行二进制和线性搜索,以查看向量 1 中的数据是否出现在向量 2 中。
谢谢你!
编辑:附加信息:当我收到此错误时,输入数据没有任何变化。我可以使用完全相同的输入数据运行完全相同的可执行文件一次并让它工作,第二次运行它,得到堆栈粉碎错误,然后运行完全相同的东西,并让它再次正常工作。
关于full-expression,标准中有一些引号,它们是:
一个完整的表达式是
- 一个未计算的操作数,
- 一个常量表达式,
- 一个INIT声明符或MEM-初始化,包括初始化的组成表达式
- 在临时对象以外的对象的生命周期结束时生成的析构函数的调用,或
- 不是另一个表达式的子表达式并且不是完整表达式的一部分的表达式。
对于初始化程序,执行实体的初始化(包括评估聚合的默认成员初始化程序)也被视为full-expression 的一部分。
现在,请考虑以下代码:
struct A{
constexpr A(int){
}
};
int main(){
constexpr A t = 0; //#1
}
Run Code Online (Sandbox Code Playgroud)
对象声明中使用的 constexpr 说明符将对象声明为 const。这样的对象应具有文字类型并应进行初始化。在任何 constexpr 变量声明中,初始化的完整表达式应为常量表达式。
看#1,它是一个声明,根据标准,在这个声明中,init-declarator是一个完整的表达式,那么初始化的完整表达式是什么,如果是A::A(0)(包括转换),它会与第5条的要点相矛盾full-expression 是一个不属于 full-expression 的表达式。显然, the A::A(0)is 是 full-expression 的一部分init-declarator,因此A::A(0)不应该是 full-expression 。
如果引用初始化的全表达式init-declarator,由于ainit-declarator不是表达式,a怎么init-declarator可能是常量表达式?我在这里很困惑,如果我的理解是错误的,那么初始化的全表达实际上是什么?
考虑标准中的一个例子
template<class T> struct A {
typedef int M;
struct B {
typedef void M;
struct C;
};
};
template<class T> struct A<T>::B::C : A<T> {
M m; // OK, A<T>?::?M
};
Run Code Online (Sandbox Code Playgroud)
评论说M参考A<T>::M,我对此表示怀疑,因为这些规则:
在类或类模板的定义中,在类模板或成员的定义点或类模板或成员的实例化期间,在非限定名称查找期间不会检查依赖基类的范围。
这意味着在非限定名称查找期间永远不会考虑依赖基类范围内的名称。
NameM是一个不合格的名称。因此不考虑Min 声明A<T>。
然后根据不合格名称查找的规则,即:
对于类 X 的成员,在成员函数体中、在默认参数中、在 noexcept 说明符中、在非静态数据成员的大括号或等号初始值设定项中或在X 定义之外的类成员,在成员的 declarator-id32 之后,应以下列方式之一声明:
- 如果 X 是 Y 类的嵌套类,则应该是 Y 的成员,或者应该是 Y 的基类的成员(此查找依次适用于 Y 的封闭类,从最内部的封闭类开始)
由于C是 的嵌套类B,因此我认为查找应从 开始B …
我试图了解std::atomic_thread_fence(std::memory_order_seq_cst);栅栏的用途,以及它们与栅栏有何不同acq_rel。
到目前为止,我的理解是,唯一的区别是 seq-cst 栅栏影响 seq-cst 操作的全局顺序 ( [atomics.order]/4)。并且只有在实际执行 seq-cst 加载时才能观察到所述顺序。
所以我想,如果我没有 seq-cst 负载,那么我可以用 acq-rel 栅栏替换所有 seq-cst 栅栏,而不改变行为。那是对的吗?
如果这是正确的,为什么我会看到这样的代码“使用栅栏实现 Dekker 算法”,它使用 seq-cst 栅栏,同时保持所有原子读/写宽松?这是该博客文章中的代码:
std::atomic<bool> flag0(false),flag1(false);
std::atomic<int> turn(0);
void p0()
{
flag0.store(true,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
while (flag1.load(std::memory_order_relaxed))
{
if (turn.load(std::memory_order_relaxed) != 0)
{
flag0.store(false,std::memory_order_relaxed);
while (turn.load(std::memory_order_relaxed) != 0)
{
}
flag0.store(true,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
}
}
std::atomic_thread_fence(std::memory_order_acquire);
// critical section
turn.store(1,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_release);
flag0.store(false,std::memory_order_relaxed);
}
void p1()
{
flag1.store(true,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
while (flag0.load(std::memory_order_relaxed))
{
if (turn.load(std::memory_order_relaxed) != 1)
{
flag1.store(false,std::memory_order_relaxed);
while …Run Code Online (Sandbox Code Playgroud) 我遇到过以下代码,其行为得到了 GCC、Clang 和 MSVC 的一致认可:
#include <concepts>
template<typename T>
auto foo(T);
template<typename U>
struct S {
template<typename T>
friend auto foo(T) {
return U{};
}
};
S<double> s;
static_assert(std::same_as<decltype(foo(42)), double>);
Run Code Online (Sandbox Code Playgroud)
现场演示: https: //godbolt.org/z/hK6xhesKM
foo()在全局命名空间中声明并推导返回类型。S<U>提供了 via 友元函数的定义foo(),它返回类型为 的值U。
我期望的是,当S用 实例化时U=double,它的定义foo()被放入全局命名空间中U并被替换,由于友元函数的工作方式,有效地如下所示:
template<typename T>
auto foo(T);
S<double> s;
template<typename T>
auto foo(T) {
return double{};
}
Run Code Online (Sandbox Code Playgroud)
因此我期望foo()的返回类型是double,并且以下静态断言应该通过:
static_assert(std::same_as<decltype(foo(42)), double>);
Run Code Online (Sandbox Code Playgroud)
然而,实际发生的情况是,所有三个编译器对此行为都持不同意见。
正如我所期望的,GCC 通过了静态断言。
Clang 失败了静态断言,因为它似乎相信 …
运行用 clang 编译的这段小代码片段时,我发现了一个奇怪的行为:
#include <iostream>
#include <exception>
#include <typeinfo>
struct Foo : public std::exception {
std::string myString;
Foo(const std::string& str) : myString(str) {}
Foo() : Foo(typeid(*this).name()) {}
};
int main()
{
Foo f;
std::cout << f.myString;
}
Run Code Online (Sandbox Code Playgroud)
typeid(*this).name()委托构造函数内部调用的指令返回nullptr导致分段错误的 a。在委托构造函数调用期间,std::exception基类尚未初始化,这似乎是此行为的原因。
我想知道这段代码是否由于某种原因格式不正确,或者这种行为是预期的。
我无法使用 g++ 重现此错误,其中代码运行良好。
仅当基类是 std::exception 时才会发生这种情况,在任何其他情况下,即使在 clang 上也能正常工作。
c++ ×10
c++17 ×3
c++11 ×2
c++20 ×2
templates ×2
atomic ×1
c++-chrono ×1
clang ×1
clang++ ×1
concurrency ×1
exception ×1
inheritance ×1
libstdc++ ×1
new-operator ×1
stdatomic ×1