小编Dai*_*ner的帖子

为什么随机设备创建成本昂贵?

C++11 通过该库支持伪随机数生成<random>

我看过多本书籍,其中提到持续构建和销毁std::random_device, std::uniform_int_distribution<>,std::uniform_real_distribution<>对象的成本非常高,并且他们建议在应用程序中保留这些对象的单个副本。

为什么创建/销毁这些对象的成本很高?这里的贵到底是什么意思呢?就执行速度可执行文件大小或其他方面而言,它是否昂贵?

有人可以提供一些解释吗?

c++ random performance c++11

31
推荐指数
2
解决办法
2637
查看次数

取消引用指针总是会导致内存访问吗?

我想知道无论编译器如何优化,取消引用指针是否总是会被转换为机器级加载/存储指令。

假设我们有两个线程,一个(我们称之为 Tom)接收用户输入并写入一个bool变量。该变量由另一个人(这是 Jerry)读取来决定是否继续循环。我们知道优化编译器在编译循环时可能会将变量存储在寄存器中。因此,在运行时,Jerry 可能会读取与 Tom 实际写入的值不同的过时值。因此,我们应该将bool变量声明为volatile

但是,如果引用指针总是会导致内存访问,那么两个线程可以使用指针来引用该变量。每次写入时,Tom 都会通过取消引用指针并将新值写入内存。每次读取时,Jerry 都可以通过取消引用同一指针来真正读取 Tom 所写的内容。这似乎比依赖于实现的更好volatile

我是多线程编程的新手,所以这个想法可能看起来微不足道且不必要。但我真的很好奇。

c c++ multithreading pointers

21
推荐指数
2
解决办法
2224
查看次数

为什么`mt19937`的默认种子是5489?

根据标准mt19937::default_seed,的值为5489u

static constexpr result_type default_seed = 5489u;
Run Code Online (Sandbox Code Playgroud)

这看起来很人为。

这背后有什么(数学或理论)原因吗?

c++ random c++11 mt19937

20
推荐指数
1
解决办法
1281
查看次数

我是否需要第二个接口类的虚拟析构函数?

我有名为“Base”和“Derived”的类。

struct Base {
    Base() = default;
    virtual ~Base() = default;
    Base(const Base&) = delete;
    Base& operator=(const Base&) = delete;

    virtual void DoStuff() = 0;
};
Run Code Online (Sandbox Code Playgroud)

“Base”类需要虚拟析构函数,这是可以理解的。我也不允许复制这个类

struct Derived : Base {
    Derived() = default;
    ~Derived() override = default;

    void DoStuff() override { /*...*/ }
};
Run Code Online (Sandbox Code Playgroud)
int main()
{
    std::shared_ptr<Base> a = std::make_shared<Derived>();
    a->DoStuff();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在让我们介绍一下其他的类,我不知道,Callable还有DerivedCallable

struct Callable
{
    virtual void Call() = 0;
};
Run Code Online (Sandbox Code Playgroud)
struct DerivedCallable : Base, Callable
{
    DerivedCallable() = default;
    ~DerivedCallable() …
Run Code Online (Sandbox Code Playgroud)

c++ inheritance virtual-functions

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

当一个跨度是另一个跨度的子跨度时,C++ 是否允许在 std::span::iterators 之间进行比较?

一般来说,C++ 不允许比较不同容器之间的迭代器。例如:

int main() {
  std::vector<int> v = {1, 2, 3};
  std::vector<int> w = {4, 5, 6};
  std::cout << v.end() == w.end() << std::endl;  // undefined!
}
Run Code Online (Sandbox Code Playgroud)

但是对于使用 创建的子跨度来说也是如此吗std::span::subspan()?例如:

int main() {
  int a[4] = { 1, 2, 3, 4};
  std::span<int> s(a);
  std::span<int> t = s.subspan(1, 2);
  std::cout << t.begin() - s.begin() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

这会打印1,这是预期的,因为内部迭代器可能只是指向底层数组的指针。问题是:该标准能否保证其正常工作?

如果是这样,更一般地说,我是否还可以比较来自内存中同一连续对象的任何跨度的迭代器?例如:

int main() {
  int a[5] = { 1, 2, 3, 4, 5};
  std::span<int> s(a);
  std::cout << (s.subspan(1, 1).end() < …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer c++20 std-span

16
推荐指数
1
解决办法
438
查看次数

C++17 中 [[nodiscard]] 的解释

在使用 C++20 的项目中,CLion 建议我添加[[nodiscard]]到我的 const 类方法定义中,例如,

class Test {
public:
    [[nodiscard]] int f(int a, int b) const {
        return a + b;
    }
}
Run Code Online (Sandbox Code Playgroud)

解释是

向成员函数添加 [[nodiscard]] 属性(在 C++17 中引入),以便在编译时突出显示哪些返回值不应被忽略。

我还检查了cppreference.com

如果从废弃值表达式(而不是强制转换为 void)调用声明为 nodiscard 的函数或按值返回声明为 nodiscard 的枚举或类的函数,则鼓励编译器发出警告。... 出现在函数声明、枚举声明或类声明中。

如果从丢弃值表达式而不是强制转换为 void,

  • 调用声明为 nodiscard 的函数,或者
  • 调用返回按值声明为 nodiscard 的枚举或类的函数,或者
  • 通过显式类型转换或 static_cast 调用声明为 nodiscard 的构造函数,或者
  • 声明为 nodiscard 的枚举或类类型的对象通过显式类型转换或 static_cast 进行初始化,

鼓励编译器发出警告。

老实说,我不太明白为什么这个位置需要这个注释。如果调用者进一步处理它们,为什么编译器会忽略我的返回值?是否有一个直观的解释来解释它到底告诉编译器什么以及为什么需要它?

c++ compiler-warnings c++17 nodiscard c++-attributes

14
推荐指数
2
解决办法
9012
查看次数

如何有效地返回 std::Optional

我想问如何以std::optional有效的方式返回 an 并且我想使用std::make_optional(). 例如,让我们有这个代码片段:

std::optional<Path> CreateCanonicalPath(const std::string_view& path)
{
  std::error_code errorCode;
  const auto result = std::filesystem::weakly_canonical(std::filesystem::u8path(path), errorCode);
  return !errorCode ? std::make_optional(result) : std::nullopt;
}
Run Code Online (Sandbox Code Playgroud)

result我特别感兴趣的是传递给是否有任何优化std::make_optional。使用起来会不会比较好std::make_optional(std::move(result))

它是否可以防止任何 RVO 或 NVRO?这result是一个局部变量,但它并不完全在 return 语句中,所以我假设编译器不能单独使用 move 。

c++ optimization c++17 stdoptional

13
推荐指数
1
解决办法
4839
查看次数

出现在同一实体的不同定义中的 lambda 表达式是否会产生相同的闭包类型?

在 C++20 中,我们可以在未计算的上下文中使用 lambda 表达式。考虑以下 C++20 代码:

foo.cpp

#include <typeinfo>

struct Foo {
  using T = decltype([]{});
};  // struct Foo

const std::type_info& getType() { return typeid(typename Foo::T); }
Run Code Online (Sandbox Code Playgroud)

主程序

#include <iostream>
#include <typeinfo>

struct Foo {
  using T = decltype([]{});
};  // struct Foo

const std::type_info& getType();

const std::type_info& getTypeFromMain() { return typeid(typename Foo::T); }

int main() {
  std::cout << std::boolalpha 
            << (getType() == getTypeFromMain());
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

标准 C++ 下程序应该输出什么?

AFAIK,GCC 和 clang 输出false。他们认为所有 lambda 表达式都应该产生不同的闭包类型,并且对于翻译单元来说是“本地的”。 …

c++ lambda language-lawyer c++20

13
推荐指数
1
解决办法
305
查看次数

在 C++ 中取消引用指向易失性结构的指针

我有一个指向某些易失性内存的指针,我试图取消引用该内存并将其复制到该结构的非限定副本(反之亦然)。存储器的格式由第三方结构定义指定。在 C 中,我可以取消引用内存,一切都很好。然而,C++抱怨它找不到合适的赋值运算符(clang的错误在这里比gcc清楚得多:候选函数(隐式复制赋值运算符)不可行:'this'参数具有类型'易失性vec',但方法是未标记为易失性)。此方法对于简单类型(例如整数)非常有效,但对于结构则失败。

在这种特殊情况下,所指向的值在读取对象期间不能更改,但我必须防止它们在读取过程中被缓存。

我发现我可以添加从易失性 T 到 T 的隐式转换吗?这给了我很多尝试的选择,但是我无法找到让它真正发挥作用的魔力。我怀疑所有这些解决方案都会失败,因为为什么不能使用非成员函数来重载赋值运算符?这将导致我的第三方定义的结构没有合适的结构,因为结构定义是第三方的,但这是理论上的,因为我什至无法让手动指定的成员函数完全工作(也许我可以创建一个包装结构有明确的东西吗?)。

下面的示例在 C 中编译并运行,但在 C++ 中失败。不幸的是,更完整的问题还有其他方面迫使 C++ 这样做。让它发挥作用的魔力是什么?

    #include <stdio.h>
    #include <stdint.h>
    struct __attribute__((__packed__)) vec {
      uint32_t addr;
      uint32_t len:24;
      uint8_t id;
    };
    struct vec first = { .addr=0xfeedface, .len=10, .id=5};
    volatile struct vec vvector;
    int main(int argc, char **argv, char **envp)
    {
      struct vec cvector;
      volatile struct vec *pvector = &vvector;
      *pvector = first;
      cvector = *pvector;
      printf("%x %d %d %d\n", cvector.addr, cvector.len, cvector.id, sizeof(cvector)); …
Run Code Online (Sandbox Code Playgroud)

c++ casting operator-overloading volatile

13
推荐指数
1
解决办法
839
查看次数

thread_local shared_ptr 对象在销毁时导致 sigsegv

我有一个程序,用于thread_local std::shared_ptr管理一些主要在本地线程访问的对象。但是,当线程加入并且线程局部shared_ptr正在析构时,如果程序是由MinGW(Windows 10)编译的,那么在调试时总是会出现SIGSEGV。以下是重现该错误的最少代码:

// main.cpp
#include <memory>
#include <thread>

void f() {
    thread_local std::shared_ptr<int> ptr = std::make_shared<int>(0);
}

int main() {
    std::thread th(f);
    th.join();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如何编译:

g++ main.cpp -o build\main.exe -std=c++17
Run Code Online (Sandbox Code Playgroud)

编译器版本:

>g++ --version
g++ (x86_64-posix-seh-rev2, Built by MinGW-W64 project) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Run Code Online (Sandbox Code Playgroud)

使用 gdb …

c++ multithreading mingw mingw-w64 c++11

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