放置新的独特指针

placement new unique pointer

本文关键字:指针      更新时间:2023-10-16

这是我的第一篇文章之一。我希望它包含正确的最小信息。请让我知道我是否省略了任何东西。

我正在尝试使用新的位置来提高以下代码块的效率(我想减少内存分配调用的数量,因为number_of_actions变量很大(> 500K((。

首先,我正在使用两个类,它们的关系可以总结为:

class txn {
public:
  int i;
  txn(): i(0) {};
};
class ActionClass {
private:
  txn* t;
public:
  ActionClass(txn* t): t(t) {};
  ~ActionClass() { delete t; }
};

我最初使用的代码为对象创建一系列指针:

std::vector<std::unique_ptr<IBatchAction>> allocate_actions(unsigned int number_of_actions) {
  std::vector<std::unique_ptr<IBatchAction>> res;
  for (unsigned int i = 0; i < number_of_actions; i++) {
    // construct the action
    std::unique_ptr<IBatchAction> act = std::make_unique<ActionClass>(new TestTxn());
    res.push_back(std::move(act));
  }
  return res;
}

更改使用位置后的代码新:

std::vector<std::unique_ptr<IBatchAction>> allocate_actions(unsigned int number_of_actions) {
  std::vector<std::unique_ptr<IBatchAction>> res(number_of_actions);
  // allocate all of the memory for actions up front to amortize the cost.
  ActionClass* actions = 
    reinterpret_cast<ActionClass*>(new char[number_of_actions * sizeof(ActionClass)]);
  txn* txns = reinterpret_cast<txn*>(new char[number_of_actions * sizeof(TestTxn)]);
  // use placement new to initialize actions and assign them to unique_ptrs
  for (unsigned int i = 0; i < number_of_actions; i++) {
    // construct the action using placement new from the memory allocated above.
    res[i].reset(new(&(actions[i])) ActionClass(new(&(txns[i])) TestTxn()));
  }
  return res;
}

在main.cpp中,i仅多次调用上述函数,时间为。结果,我在segfault之前得到以下堆栈跟踪:

#0  std::unique_ptr<IBatchAction, std::default_delete<IBatchAction> >::~unique_ptr (
    this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/5/bits/unique_ptr.h:236
#1  std::_Destroy<std::unique_ptr<IBatchAction, std::default_delete<IBatchAction> > > (
    __pointer=<optimized out>) at /usr/include/c++/5/bits/stl_construct.h:93
#2  std::_Destroy_aux<false>::__destroy<std::unique_ptr<IBatchAction, std::default_delete<IBatchAction> >*> (__last=<optimized out>, __first=0x7ffff7f06018)
    at /usr/include/c++/5/bits/stl_construct.h:103
#3  std::_Destroy<std::unique_ptr<IBatchAction, std::default_delete<IBatchAction> >*> (
    __last=<optimized out>, __first=<optimized out>) at /usr/include/c++/5/bits/stl_construct.h:126
#4  std::_Destroy<std::unique_ptr<IBatchAction, std::default_delete<IBatchAction> >*, std::unique_ptr<IBatchAction, std::default_delete<IBatchAction> > > (__last=0x7ffff7fc9510, 
    __first=<optimized out>) at /usr/include/c++/5/bits/stl_construct.h:151
#5  std::vector<std::unique_ptr<IBatchAction, std::default_delete<IBatchAction> >, std::allocator<std::unique_ptr<IBatchAction, std::default_delete<IBatchAction> > > >::~vector (this=0x7fffffffd910, 
    __in_chrg=<optimized out>) at /usr/include/c++/5/bits/stl_vector.h:424
#6  time_workload_creation (exp_conf=...) at start_batch/main.cc:18
#7  0x000000000040320c in main (argc=<optimized out>, argv=<optimized out>)
    at start_batch/main.cc:44

我是新概念的新手。以下是我用来编写上述代码的内容:

  1. 我可以使用新的位置在共享_ptr中重置对象吗? - 使用重置以分配使用位置创建的新对象的新对象
  2. 在shared_ptr上的新位置在删除时会导致SEG故障 - 一个非常相似的问题。这个答案确实对我有帮助:(

我可能做出明显错误的事情,但我无法弄清楚。帮助?如果您需要从MAIN(简化(的实际代码,则在这里(Action.H包含我讨论过的功能(。

#include "actions.h"
#include <chrono>
#include <vector>
void time_workload_creation(unsigned int act_num) {
  std::chrono::system_clock::time_point time_start, time_end;
  std::vector<double> results;
  for (unsigned int i = 0; i < 10; i++) {
    time_start = std::chrono::system_clock::now();
    auto workload = allocate_actions(act_num);
    time_end = std::chrono::system_clock::now();
    results.push_back(
        std::chrono::duration_cast<std::chrono::milliseconds>(time_end - time_start).count());
  }
  for (unsigned int i = 0; i < 10; i++) {
    std::cout << i << "tt" <<  
      act_num << "tt" <<  
      results[i] << "tt" <<  
      act_num / results[i] << std::endl;
  }
};
int main(int argc, char** argv) {
  time_workload_creation(1000000);
  return 0;
}

使用:GCC版本5.4.0 20160609(Ubuntu 5.4.0-6ubuntu1〜16.04.4(

更改使用位置后的代码新:
[...]

此代码具有未定义的行为。您可以使用new[]创建一个char数组,然后重置N unique_ptr对象,该对象将尝试删除N不同的ActionClass对象。您期望如何工作?您需要使用delete[]释放char的数组,而不是在char数组的块上使用N delete操作。

同样,每个ActionClass都会尝试将其delete进行txn对象,但这也完全不确定,因为您没有分配N txn对象,您分配了char的另一个数组。

这不是内存分配的工作方式。您不能分配大块,然后分配其中的部分。(好吧,您可以,但仅通过编写自己的自定义(DE(分配功能或分配器(。