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

时间:2019-05-14 10:08:52

标签: c++ swig

在向量超出范围后,我可以强制std :: 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需要原始指针,实际上是有意的内存泄漏。但是,我仍然希望能够在构造数据本身时利用向量特征。

7 个答案:

答案 0 :(得分:7)

有可能,但您永远不要这样做。强迫向量离开内存泄漏是一个可怕的主意,如果您需要这种东西,则需要重新考虑设计。 std :: vector是一种资源管理类型,其主要目标之一是确保我们不会泄漏。永远不要试图打破它。

现在,要回答您的特定问题:std::vector将分配器类型作为第二个模板参数,默认为std::allocator<T>。现在,您可以编写一个不释放任何内存的自定义分配器,并将其与向量一起使用。编写自定义分配器并不是一件容易的事,因此在这里我将不做介绍(但是您可以通过Google找到这些教程)。

如果您确实要使用自定义分配器,则必须确保向量永远不会触发增长操作。原因是在容量增加期间,向量会将数据移动/复制到新位置,并使用分配器释放旧内存。如果使用泄漏的分配器,那么在增长过程中,您不仅会保留最终数据,而且还会保留旧的内存,我确定您不想保留这些旧的内存。因此,请确保创建具有完整容量的向量。

答案 1 :(得分:4)

否。

未实现矢量以防止内存泄漏,并且该接口也未提供创建矢量的方法。

您无法“窃取”内存(从向量中删除其所有权),这可能有点丢人。

对不起,但是您将不得不复制(如您现在所做的那样),或者不使用向量。

答案 2 :(得分:3)

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;
}

正如其他答案所说,您永远不要这样做。

答案 3 :(得分:3)

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

例如:(样板大多来自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;
}

变为有效。

答案 4 :(得分:2)

不确定,是的。

您可以创建一个客户allocator,在取消分配=>泄漏时不执行任何操作

或者您可以在堆上创建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;
}

答案 5 :(得分:0)

否。

您做错了。 取而代之的是返回向量,从而得出生命周期:

编写自己的特殊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;
}

答案 6 :(得分:0)

在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;
}