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