使用自定义分配器的std :: promise似乎使用全局新

时间:2015-11-10 19:36:28

标签: c++11 promise future allocator

上下文:我正在编写一个库,它为许多stdlib数据结构中的自定义分配器公开,以便为想要自定义内存分配以实现实时性能的用户提供。

我想使用std::promisestd::future的自定义分配器。我的理解是,当一个分配器传递给std::promise时,它的future对象也会使用该自定义分配器。

我的测试会覆盖全局new和delete以跟踪调用默认运算符的次数。我还实现了一个使用mallocfree的自定义分配器,但使用不同的状态来计算分配/解除分配(在实际示例中,它将替换为实时安全分配器)。

当我打电话给std::promise::set_value来表示"大"对象,全局运算符new和delete被调用,即使promise是使用自定义分配器构造的。

这是一个基本的例子。 (为简洁起见,删除了分配器样板,您可以在Gist上看到完整的,可编译的版本:https://gist.github.com/jacquelinekay/a4a1a282108a55d545a9

struct Foo {
  std::vector<int, InstrumentedAllocator<int>> bar;
};

int main(int argc, char ** argv) {
  (void) argc;
  (void) argv;
  InstrumentedAllocator<void> alloc;

  std::promise<Foo> promise_(std::allocator_arg, alloc);
  std::shared_future<Foo> future_ = promise_.get_future().share();

  // Start a thread that blocks for a few ms and sets the future value
  std::thread result_thread(
    [&promise_]() {
      Foo result;
      result.bar.push_back(1);
      result.bar.push_back(2);
      result.bar.push_back(3);
      // test_init starts counting calls to global new/delete
      // (stored in variables global_runtime_allocs/deallocs)
      test_init = true;
      std::this_thread::sleep_for(std::chrono::milliseconds(5));
      promise_.set_value(result);
      test_init = false;
    }
  );
  future_.wait();
  result_thread.join();
  std::cout << "Runtime global allocations: " << global_runtime_allocs << " (expected: 0)" << std::endl;
  std::cout << "Runtime global deallocations: " << global_runtime_deallocs << " (expected: 0)" << std::endl;
}

此示例的全局运算符new也会打印&#34;运行时&#34;的大小。分配(来自std::promise::set_value),产生此输出:

$ clang++ promise_allocator.cpp -std=c++11 -lpthread
$ ./a.out
Allocation size: 16
Runtime global allocations: 1 (expected: 0)
Runtime global deallocations: 1 (expected: 0)

我在gcc 4.8和Clang 3.4上得到了相同的结果。这是对标准的正确解释吗?我希望set_value能够使用promise的分配器。

2 个答案:

答案 0 :(得分:1)

结合使用调试器回溯并结合GCC的stdlib实现,我已经找到为什么会发生这种情况,尽管我自己没有解决方案或解决方法。

std::promise::set_value调用其未来的内部函数future::_M_set_result。 [1]将函数对象__res传递给此函数会调用_Function_base的构造函数,可能是因为函数的签名未通过引用传递__res_。 [2] _Function_base的构造函数调用_M_init_functor,如果函数使用本地存储或分配新对象,则执行新的放置。 [3]由于某些原因我还没有确定,future内部使用的函数不使用本地存储,因此在构造函数中分配。

从略读我能找到的标准的工作草案[4],该标准并未具体说明promise中预期的分配行为。但是,我不能控制promise内部使用的函数的分配行为是不方便的,我可能会在gcc中提出一个关于它的错误。

  1. https://github.com/gcc-mirror/gcc/blob/gcc-4_8_4-release/libstdc%2B%2B-v3/include/std/future#L985
  2. https://github.com/gcc-mirror/gcc/blob/gcc-4_8_4-release/libstdc%2B%2B-v3/include/std/future#L352
  3. https://github.com/gcc-mirror/gcc/blob/gcc-4_8_4-release/libstdc%2B%2B-v3/include/std/functional#L1957
  4. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf

答案 1 :(得分:1)

这似乎是4.9版本系列libstdc ++中的一个错误,该错误在版本5发行版系列中得到修复。使用version 5.1或更高版本在Wandbox上运行您的要点仅产生输出:

Runtime global allocations: 0 (expected: 0)
Runtime global deallocations: 0 (expected: 0)