如何创建指向向量的指针向量

Posted

技术标签:

【中文标题】如何创建指向向量的指针向量【英文标题】:how to create a vector of pointers to a vector 【发布时间】:2013-04-15 23:40:52 【问题描述】:

我有一个指向向量的指针:

vector<double> mv;
mv.push_back(233);
mv.push_back(234);
mv.push_back(654);
vector<double>* new_mv_pt = new vector<double> (3);
new_mv_pt = &mv;    

cout << (*new_mv_pt)[1] << endl;    

如何创建另一个向量来存储这个指向向量的指针? 我正在尝试这个...

    vector<double*> vop = new vector<double> (3);

vop.push_back(*new_mv_pt);

cout << (*vop)[1] << endl;

但它不起作用。我正在尝试的可能吗?:

【问题讨论】:

首先,得到你的答案。其次,意识到这是一个可怕的想法,因为您正在消除向量为您管理内存的能力,这(至少)是最初使用它的一半。 我只是想弄清楚为什么他首先有一个指向向量的指针。这样做在概念上没有意义,特别是如果它在同一个函数/类中。 【参考方案1】:

哇,慢点!

你正在用你的记忆做一些非常疯狂的事情,所以让我们从头开始吧。

您有一个包含 3 个元素的向量。您想使用指针引用该向量。让我们看看它的外观:

vector<double> mv;
mv.push_back(233);
mv.push_back(234);
mv.push_back(654);
// No no no no! You don't have to `new` a pointer that 
// you're going to assign to something else!
// This is called a memory leak, and it means you've just wasted (!!!)
// C++ memory! Don't do it 
// vector<double>* new_mv_pt = new vector<double> (3);
// Instead, do this:
vector<double>* ptr_to_mv = &mv; // No leak, immediately points to a vector<double> mv;

这会处理第一个问题。现在,让我们更深入地了解它。您想要存储对向量的引用向量。好吧,这听起来很公平。有几种方法可以解决。让我们回到mv等的例子:

vector<double> mv;
mv.push_back(233);
mv.push_back(234);
mv.push_back(654);
vector<double>* ptr_to_mv = &mv;
// So far so good. Now, based on your question, you want
// to have a list of these to point to. So:
vector<vector<double>*> vop;
vop.push_back( ptr_to_mv ); // All clean.

此时,在您的代码中,您必须使用.at()operator[] 访问vop 才能访问vector&lt;double&gt;*,然后使用* 取消引用它或使用-&gt; 进行处理直接:

std::vector<double>* ptr_to_vector = vop[0]; // Got my pointer
std::cout << ptr_to_vector->at( 0 ) << std::endl; // Prints '233'

这会打印 233,因为所有这些都是您引用的 mv。在另一个答案的评论中,您说当您删除这些指针时,您会得到一个断言。 这是应该发生的,因为你删除了两次!

还记得mv,您很久以前就声明过吗?好吧,你没有让它成为一个动态向量。你没有new 它,它不是指针。所以当函数退出时,它会自动删除自己——它会调用它的析构函数并死在堆栈上。如果您查看ptr_to_vectorptr_to_mv,它们都在引用mv,它会自行清理。

如果你在它上面调用 delete,你是在尝试在 mv 上调用 delete(这就是你所指向的)并且你正在双重删除!强>

所以,当你有一个指向mv 的指针时,不要删除它。它是一个基于堆栈的变量。它会自行清理。

还在关注吗?太好了,让我们再深入一点:

现在,如果有一个 原因 你需要 new 向上一个向量,你不要用旧指针指定覆盖它(正如我之前告诉你的,你会留下内存) .您制作了一个全新的指针:

// Our vector of double vector pointers
vector<vector<double>*> vop;

vector<double> mv;
mv.push_back(233);
mv.push_back(234);
mv.push_back(654);

// References a stack variable: don't delete
vector<double>* ptr_to_mv = &mv;
vop.push_back( ptr_to_mv );

// Makes a fresh copy of mv. You must delete this
// manually
vector<double>* fresh_ptr = new vector<double>( mv );
(*fresh_ptr)[0] = 1337;
// changes only data in fresh_ptr, not `mv`
vop.push_back( fresh_ptr );

/* Blah blah blah, work */
// Functions about to exit, gotta clean up!
delete fresh_ptr;
//delete ptr_to_mv; // NO.
//delete vop[0]; // NO!
//delete vop[1]; // ... Already deleted from fresh_ptr
// ... This is going to get tedious if we don't have a fresh_ptr
// for every vector we need!

上面显示了问题:我们有 2 个指针,都在 vop 内部,其中一个需要通过调用 delete 来清理,另一个不需要,因为它只是对 mv 的引用,它会自动清理!循环遍历向量并删除所有内容将导致该讨厌的断言发生。我们如何处理它并仍然获得我们需要的清理?

肮脏而快速的解决方案 1 是只需 delete vop[1]/fresh_ptr 并完成它。更好的解决方案是,每当您 new 获取资源时,您将其包裹在称为 std::unique_ptr 的奇妙事物中。代码将如下所示:

// Our vector of double vector pointers. Non-owning
vector<vector<double>*> vop;

vector<double> mv;
mv.push_back(233);
mv.push_back(234);
mv.push_back(654);

// References a stack variable: don't delete
vector<double>* ptr_to_mv = &mv;
vop.push_back( ptr_to_mv );

// Makes a fresh copy of mv
// puts it inside a std::unique_ptr,
// which, like a stack-based vector,
// can clean itself up
std::unique_ptr<vector<double>> fresh_ptr( new vector<double>( mv ) );
vop.push_back( fresh_ptr.get() );

/* Blah blah blah, work */
// Functions about to exit, gotta clean up!
//delete fresh_ptr; // Not necessary
//delete ptr_to_mv; // Nope.jpg

然后,删除所有注释掉的代码,突然间,你的东西就干净了!

当然,现在,我要问你的最后一个问题是: 你到底在做什么,需要所有这些指向向量指针引用的指针?

【讨论】:

这非常有帮助。你给了我很大的压力。非常感谢。 这是一个非常简单的问题的非常详细的答案。楼主你是专业的! +1【参考方案2】:

是的,但您需要这样做:

vector<vector<double>*> vop;

因为您正在寻找向量指针列表。

你有什么:

vector<double *> vop

只是double 指针的向量。

你也只想要这个:

vop.push_back(new_mv_pt); //  <- No asterisk (you don't want to de-reference it)

【讨论】:

如何删除两个指针以避免内存泄漏?我尝试删除 new_mv_pt 并且在运行时出现某种断言错误。有什么问题? 两个指针是什么意思?你的意思是new_mv_pt 和向量中的那个吗? 好吧,当我尝试删除 new_mv_pt 而不是在指针向量中时,它不起作用,并且在运行时出现某种断言错误。最后我想知道如何安全地删除它。【参考方案3】:

这里有内存泄漏:

vector<double>* new_mv_pt = new vector<double> (3);
new_mv_pt = &mv;

您正在堆上创建一个vector&lt;double&gt;,将其地址存储在new_mv_pt,然后mv 地址覆盖该地址。 vector&lt;double&gt; 仍然存在于堆上,但您已经永久丢失了它的地址(因此无法delete 它或用它做任何其他事情)。

这段代码:

vector<double*> vop = new vector<double> (3);
vop.push_back(*new_mv_pt);
cout << (*vop)[1] << endl;

不起作用,因为vopdouble*s 的向量,而您正试图将vector&lt;double&gt; 插入其中。正确方法见Ben's answer。

【讨论】:

以上是关于如何创建指向向量的指针向量的主要内容,如果未能解决你的问题,请参考以下文章

当向量在内部类中时,如何删除指向对象的向量指针

如何从 C++ 中的“指向对象的指针”向量访问对象

从 2D 向量创建 1D 向量的函数(错误:表达式必须具有指向对象的指针类型)

指向类方法 QT 的指针向量

C++:使用 int 指针指向在函数内部创建的向量

如何访问包含指向字符串的指针的向量的元素?