我可以强制 std::vector 留下内存泄漏吗?

Can I force std::vector to leave a memory leak?

我可以强制 std::vector 在 vector 超出范围后不释放它的内存吗?

例如,如果我有

int* foo() {
    std::vector<int> v(10,1); // trivial vector
    return &v[0];
}

int main()
{
    int* bar = foo();
    std::cout << bar[5] << std::endl;
}

不保证这些值仍可在此处访问。

我目前只是在做这个

int* foo() {
  std::vector<int> v(10,1);
  int* w = new int[10];
  for (int i=0; i<10; i++) {
    w[i] = v[i];
  }
  return w;
}

但是重新填充一个全新的数组有点浪费。有没有办法强制 std::vector 不删除它的数组?

注意:我没有返回向量本身,因为我正在使用 SWIG 将 c++ 与 python 连接起来,而 ARG_OUTVIEW_ARRAY 需要一个原始指针,事实上,这是一个有意的内存泄漏。但是,我仍然希望能够在构建数据本身时利用向量特征。

没有

向量未实现内存泄漏,接口未提供创建向量的方法。

您不能 "steal" 内存(从向量中删除它的所有权),这 可能有点遗憾。

抱歉,您将不得不复制(就像您现在所做的那样),或者不使用矢量。

不确定但是,是的。

您可以创建一个 custum allocator 在 deallocate => leak

时什么都不做

或者您可以直接在堆上创建 vector 这样它就会泄漏。

int* foo() {
    std::vector<int>* v = new std::vector<int>(10,1); 
    return &((*v)[0]);
    // no delete
}

int main()
{
    int* bar = foo();
    std::cout << bar[5] << std::endl;
}

这是可能的,但你永远不应该这样做。强制向量留下内存泄漏是一个糟糕的主意,如果您需要这样的东西,那么您需要 re-think 您的设计。 std::vector 是一种资源管理类型,其主要目标之一是确保我们没有泄漏。永远不要试图打破它。

现在,回答您的具体问题:std::vector 将分配器类型作为第二个模板参数,默认为 std::allocator<T>。现在您可以编写一个不释放任何内存的自定义分配器并将其与您的向量一起使用。编写自定义分配器并不是一件很简单的工作,所以我不打算在这里描述它(但你可以 Google 找到教程)。

如果您真的想使用自定义分配器,那么您必须确保您的向量永远不会触发增长操作。因为在容量增长期间,矢量将 move/copy 数据到新位置并使用分配器释放旧内存。如果您使用泄漏的分配器,那么在增长过程中您不仅会保留最终数据,还会保留我确信您不想保留的旧记忆。因此,请确保您创建的向量具有完整容量。

没有

而你做错了。 Return 向量而不是因此生命周期计算得出:

编写您自己的特殊 Python 记忆向量 class,类似于(最粗略的):

template <typename T>
class python_vector
{
    T* buffer_;
public:
    python_vector(size_t n, const T& value) : buffer_{new T(n)}
    {}
    // copy, assignment, operator[](), *etc*
    ~python_vector()
    {
        // DO NOTHING!
    }
}

python_vector<int> foo() {      
    python_vector<int> v(10,1);
    // process v
    return v;
}

int main()
{
    python_vector<int> bar = foo();  // copy allusion will build only one python_vector here
    std::cout << bar[5] << std::endl;
}

vector是为了防止泄露而设计的。

但如果你想搬起石头砸自己的脚,那也是可能的。以下是防止向量释放其内部数组的方法:

int *foo()
{
    std::vector<int> v(10,1);

    int *ret = v.data();
    new (&v) std::vector<int>; // Replace `v` with an empty vector. Old storage is leaked.
    return ret;
}

正如其他答案所说,你永远不应该这样做。

这是个坏主意,但可以通过创建一个不会像其他答案中所说的那样取消分配的自定义分配器来实现。

例如:(样板主要来自 cppref

#include <cstdlib>
#include <new>
#include <vector>

template <typename T>
struct LeakingAllocator 
{
  using value_type = T;
  LeakingAllocator() = default;

  template <typename U> constexpr LeakingAllocator(const LeakingAllocator<U>&) noexcept {}

  T* allocate(std::size_t n) 
  {
    if(n > std::size_t(-1) / sizeof(T)) throw std::bad_alloc(); // check for overflow

    if(auto p = static_cast<T*>(std::malloc(n*sizeof(T)))) return p; // return p if malloc returns a valid object
    throw std::bad_alloc(); // otherwise just throw.
  }

  void deallocate(T* p, std::size_t) noexcept { /*leak intentionally*/ }
};


template <typename T, typename U>
bool operator==(const LeakingAllocator<T>&, const LeakingAllocator<U>&) { return true; }
template <typename T, typename U>
bool operator!=(const LeakingAllocator<T>&, const LeakingAllocator<U>&) { return false; }

template <typename T>
using LeakingVector = std::vector<T, LeakingAllocator<T>>;

然后像

这样的代码
int* ret()
{
    LeakingVector<int> a;
    a.resize(10);
    return &a[0];
}

int main()
{
    auto ptr = ret();
    *ptr = 10;
    std::cout << *ptr;
}

生效。

在 C++ 中,您很可能会这样写:

auto foo()
{
    std::vector<int> v(10,1); // trivial vector
    return v;
}

int main()
{
    const auto bar = foo();
    std::cout << bar[5] << std::endl;
}