小编Adr*_*ian的帖子

新分配一个指向函数的指针是否合法?

函数指针不是普通的数据指针,因为它们不能存储在 void* 指针中。尽管如此,我似乎可以像下面的代码一样将函数指针的副本存储在动态内存中(在 gcc 和 clang 中)。根据 C++ 标准,这样的代码是否合法,或者这是某种编译器扩展?

此外,指向函数指针的结果指针表现为普通数据指针:我可以将它存储在 void* 中,并通过 static_cast 从 void* 中检索它。标准是否保证这种行为?

int main()
{
  extern void fcn();
  void (*fcnPtr)() = &fcn;
  void (**ptrToFcnPtr)() = nullptr;

  //Make the copy of fcnPtr on the heap:
  ptrToFcnPtr = new decltype(fcnPtr)(fcnPtr);
  //Call the pointed-to function : 
  (**ptrToFcnPtr)();

  //Save the pointer in void* :
  void *ptr = ptrToFcnPtr;
  //retrieve the original ptr: 
  auto myPtr = static_cast< void(**)() > (ptr) ; 
  //free memory:
  delete ptrToFcnPtr ;

}
Run Code Online (Sandbox Code Playgroud)

c++

33
推荐指数
2
解决办法
1385
查看次数

std :: shared_mutex是否偏爱作者而不是读者?

从C ++ 17(C ++ 14)开始,我们有了std :: shared_(timed_)mutex类。Qt长期以来都有一个类似的类QReadWriteLock。QReadWriteLock的 文档说:

为了确保不会永远阻止写入者,即使有阻塞的写入者正在等待访问,即使当前仅由其他读取者访问,尝试获取锁的读取器也不会成功。同样,如果某个写程序访问了该锁,而另一个写程序进入了该写程序,则该写程序的优先级高于可能也在等待的所有读程序。

因为这当然是一个合理的属性,所以我想知道 std :: shared_mutex和std :: shared_timed_mutex的行为是否类似?

c++ multithreading

10
推荐指数
2
解决办法
128
查看次数

在 std::launder 之前,所有 std::vector 的实现都是不可移植的吗?

当在实例emplace_back()上调用时std::vector,会在先前分配的存储中创建一个对象。这可以通过 Placement-new 轻松实现,它非常便携。但现在,我们需要访问嵌入的元素而不调用未定义的行为。

从这篇文章中 我了解到有两种方法可以做到这一点

  1. 使用placement-new返回的指针: auto *elemPtr = new (bufferPtr) MyType();

  2. 或者,从 C++17 开始,std::launder所转换的指针bufferPtr
    auto *elemPtr2 = std::launder(reinterpret_cast<MyType*>(bufferPtr));

第二种方法可以很容易地推广到这样的情况,即我们有很多对象放置在相邻的内存位置,如std::vector. 但在 C++17 之前人们做了什么?一种解决方案是将placement-new 返回的指针存储在单独的动态数组中。虽然这当然是合法的,但我认为它并没有真正实现 std::vector [此外,单独存储我们已经知道的所有地址是一个疯狂的想法]。另一个解决方案是存储lastEmplacedElemPtrinside std::vector,并从中删除适当的整数 - 但由于我们实际上没有MyType对象数组,这可能也是未定义的。事实上,此 cppreference 页面中的一个示例声称,如果我们有两个相同类型的指针比较相等,并且其中一个可以安全地取消引用,则取消引用另一个可能仍然是未定义的。

那么,在 C++17 之前有没有办法以可移植的方式实现 std::vector 呢?或者也许 std::launder 确实是 C++ 的一个关键部分,当涉及到新的放置时,自 C++98 以来就缺失了?

我知道这个问题表面上与SO上的许多其他问题相似,但据我所知,他们都没有解释如何合法地迭代由placement-new构造的对象。事实上,这一切都有点令人困惑。例如,示例形式的cppreference 文档中的 std::aligned_storage注释 似乎表明 C++11 和 C++17 之间存在一些变化,并且简单的别名违规reinterpret_cast在 C++17 之前是合法的 [无需std::launder]。类似地,在文档 的示例中,std::malloc 他们只是对返回的指针进行指针算术 …

c++ placement-new language-lawyer c++11

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

glVertexAttribPointer 调用中是否强制转换为 void* 是合法的 C++?

这实际上是一个关于C++的问题,而不是关于OpenGL的问题。我正在关注有关 OpenGL 的本教程(我刚刚开始),作者使用 C++(不是 C)。我的问题是glVertexAttribPointer 需要一个偏移参数作为const void*。由于此参数只是告诉 OpenGL 给定的顶点属性第一次出现在使用 复制的顶点数组中的位置glBufferData(),因此我希望它应该是std::ptrdiff_t类型。SO 上的这篇void*文章解释了为什么用作参数类型的原因,但我想知道为什么这种用法在 C++ 中是合法的。例如,提到的教程只是简单地转换为以void*字节为单位的偏移量值,如下面的调用所示:

glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3* sizeof(float)));
Run Code Online (Sandbox Code Playgroud)

在我看来,这种方法不合法,因为cpprefence文档reinterpret_cast说

任何整型或枚举类型的值都可以转换为指针类型。转换为足够大小的整数并返回到相同指针类型的指针保证具有其原始值,否则无法安全地取消引用结果指针(不保证相反方向的往返转换,相同的指针可能具有多个整数表示)

因此,如果我正确理解这一点,std::ptrdiff_t偏移量的值(这似乎是这里需要的)在转换为void*. 我想念什么?

c++ opengl

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

聚合初始化与统一初始化

我对 C++11 统一初始化了解得越多,我就越困惑。在 Effective Modern C++(第 55 页)中的 Scott Meyers 说,声明

Widget w2{};
Run Code Online (Sandbox Code Playgroud)

始终调用默认构造函数(即使存在带有std::initializer_list参数的构造函数)。

乍一看,这似乎与 Stroustrup 书“C++ 编程语言”的第 4 版一致,例如根据第 1200 页上的表格声明

std::atomic<T> x;
Run Code Online (Sandbox Code Playgroud)

使原子变量未初始化,而

std::atomic<T> x {};
Run Code Online (Sandbox Code Playgroud)

调用“默认构造函数”,以便 x 表示一个值初始化的 T 对象。

但是,我无法相信std::atomic<T> x;不再调用 C++11 中的默认构造函数,所以我在这里完全感到困惑。

最后,在查看了 C++11 标准(n3337 草案)后,我的困惑更大了。在第 1102 页,我们有:

template <> struct atomic<integral > {
  //[...] list of non-constructor functions
  atomic() noexcept = default;
  constexpr atomic(integral ) noexcept;
  atomic(const atomic&) = delete;
  //[...] other non-constructor functions
};
Run Code Online (Sandbox Code Playgroud)

在第 1104 页(第 29.5.5 点)我们看到 …

c++

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

dynamic_cast与动态库边界

我正在阅读``使用Qt 4进行C ++ GUI编程'',在其中找到以下语句

与标准C ++ dynamic_cast()不同,Qt的qobject_cast()可以在动态库边界上正常运行。

类似的声明出现在官方Qt文档中,网址为

https://doc.qt.io/qt-5/qobject.html#qobject_cast

这是什么意思?在哪里我们不能在C ++中使用dynamic_cast?虚函数呢?将它们与动态链接的库一起使用是否安全?

c++

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

std :: mutex是否偏爱拥有它的线程?

我试图了解自旋锁互斥体是如何工作的,因此我编写了一个简单的代码(如下所示),该代码在自旋锁(或std::)互斥体的保护下,测量来自不同线程的指令交织。

令人惊讶的是,它表明(至少在gcc中)std :: mutex(与spinlock互斥锁相比)似乎更喜欢拥有它的线程,从而导致非常小的指令交织(最多5%),除非所讨论的指令是非常快(例如增加计数器)。在这种情况下,我们甚至可以得到50%。自旋锁互斥量至少提供80%(通常超过90%)。

这是众所周知的事实吗?或者下面我的代码有错误?

我的意思是,我知道根据经验法则说,互斥锁应该始终在最短的时间内锁定。但是我坚信这是事实,因为我们要减少线程的序列化,而不是因为std :: mutex支持拥有的线程...

这是代码:

#include<atomic>
#include<thread>
#include<iostream>
#include<chrono>
#include<mutex>


class SpinLockMutex{
    std::atomic_flag m_flag = ATOMIC_FLAG_INIT;
public:
    void lock()   { while( m_flag.test_and_set(std::memory_order_acquire) )  /*do nothing*/ ; }
    void unlock() { m_flag.clear(std::memory_order_release) ; }
};//class SpinLockMutex


// ******************************************
// // // std::mutex vs SpinLockMutex 
//SpinLockMutex globalMutex;
std::mutex globalMutex;
// ******************************************


// This class helps to start threads at the same time : 
class Starter{
    mutable std::mutex m_m;
    bool m_ready = false;
public:
    bool isReady() const …
Run Code Online (Sandbox Code Playgroud)

c++ multithreading

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

在 nullptr 上调用无状态类的非静态成员函数是否合法?

考虑以下代码:

int main()
{
    struct EmptyStruct{
        void nonstatic_mf() const { std::cout <<"EmptyStruct\n"; }
    };


    EmptyStruct *esptr = nullptr;
    esptr->nonstatic_mf(); 
}  
Run Code Online (Sandbox Code Playgroud)

这是一个合法的 C++(它似乎在 gcc 和 clang 中工作)?

c++ pointers member-functions language-lawyer

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