visual-c++ - 自定义分配器vs.promise和打包任务

原文 标签 visual-c++ c++11 boost language-lawyer c++14

标准promise / packaged_task的分配器构造函数是否应该仅将分配器用于状态对象本身,还是应该为所有(内部)相关对象保证使用分配器?

[futures.promise]: "...allocate memory for the shared state"
[futures.task.members]: "...allocate memory needed to store the internal data structures"



特别是以下错误或功能?

* MSVC 2013.4,Boost 1.57,short_alloc.h by Howard Hinnant

示例1
#define BOOST_THREAD_VERSION 4
#include <boost/thread/future.hpp>
#include "short_alloc.h"
#include <cstdio>

void *operator new( std::size_t s ) {
    printf( "alloc %Iu\n", s );
    return malloc( s );
}

void operator delete( void *p ) {
    free( p );
}

int main() {

    const int N = 1024;
    arena< N > a;
    short_alloc< int, N > al( a );

    printf( "[promise]\n" );
    auto p = boost::promise< int >( std::allocator_arg, al );
    p.set_value( 123 );

    printf( "[packaged_task]\n" );
    auto q = boost::packaged_task< int() >( std::allocator_arg, al, [] { return 123; } );
    q();

    return 0;

}

输出:
...
[promise]
alloc 8
alloc 12
alloc 8
alloc 24
[packaged_task]
alloc 8
alloc 12
alloc 8
alloc 24

FWIW,具有默认分配器的输出为
...
[promise]
alloc 144
alloc 8
alloc 12
alloc 8
alloc 16
[packaged_task]
alloc 160
alloc 8
alloc 12
alloc 8
alloc 16

示例2

AFAICT,MSVC的std::mutex会不可避免地进行堆分配,因此使用它的std::promise也会这样做。这是一致的行为吗?

最佳答案

N.B.您的代码有几个问题。在C++ 14中,如果替换operator delete(void*),那么还必须替换operator delete(void*, std::size)t)。您可以使用功能测试宏来查看编译器是否要求:

void operator delete( void *p ) {
    free( p );
}
#if __cpp_sized_deallocation
// Also define sized-deallocation function:
void operator delete( void *p, std::size_t ) {
    free( p );
}
#endif

其次,正确的size_t printf格式说明符是zu而不是u,因此您应该使用%Izu

AFAICT, MSVC's std::mutex does an unavoidable heap allocation, and therefore, so does std::promise which uses it. Is this a conformant behaviour?


std::mutex是否应使用动态分配无疑是个问题。它的构造函数不能,因为它必须是constexpr。它可能会延迟分配,直到第一次调用lock()try_lock(),但lock()并未将获取资源失败列为有效错误条件,这意味着try_lock()如果无法分配所需的资源,则可能无法锁定无竞争的互斥锁。斜视一下是允许的,但并不理想。

但是关于您的主要问题,正如您所引用的,该标准仅针对promise指出了这一点:

The second constructor uses the allocator a to allocate memory for the shared state.



那没有说 promise 需要的其他资源。可以合理地假设任何同步对象(例如互斥体)都是共享状态的一部分,而不是 promise ,但是措辞不需要将分配器用于共享状态成员所需的内存,而仅用于共享状态所需的内存本身。

对于packaged_task,措词范围更广,暗示所有内部状态都应使用分配器,尽管可以说这意味着分配器用于获取存储的任务和共享状态的内存,但又一次表明共享状态的成员不必使用分配器。

总而言之,我不认为该标准是否100%明确是否允许MSVC实现,但是恕我直言,不需要mallocnew的额外内存的实现会更好(这就是libstdc++ <future>实现的工作方式)。

相关文章:

c++ - 确保功能的仅一个实例正在运行?

c++ - 如何在C++中为 vector 创建getter和setter?

c++ - 无法使用SFINAE,在MSVC10中键入traits和static_assert

c++ - 捕获C++文件IO期间所有错误(或ios对象中的任何错误)的最佳实践

c++ - 从C++程序传递在cmd pmt中使用空格执行文件名

python - 无法安装Caffe的“提升”先决条件

winapi - 如何枚举媒体流?

c++ - std::map的这种可移动类型有什么问题?

c++ - 重载新运算符-此代码不应该产生错误

c++ - Boost buffer_sequence_adapter中的奇怪编译错误