我想向您展示这个非常简单的示例,其目的是对动态分配的一些字符串进行排序,并清理重复大小的向量并释放无用的占用内存。
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
void print_v (vector<string *>& v)
{
cout << "----" << endl;
for (string*& str : v)
cout << *str << " ";
cout << endl << "----" << endl;
}
typedef string * string_ptr;
int main()
{
vector<string_ptr> v;
v.push_back(new string("aba"));
v.push_back(new string("baba"));
v.push_back(new string("saba"));
v.push_back(new string("aba"));
v.push_back(new string("naba"));
v.push_back(new string("aba"));
v.push_back(new string("saba"));
v.push_back(new string("laba"));
print_v(v);
sort(v.begin(), v.end(), [](const string_ptr &a, const string_ptr &b){
return a->compare(*b) < 0;
});
auto last = unique(v.begin(), v.end(), [](const string_ptr &a, const string_ptr &b) {
return a->compare(*b) == 0;
});
print_v(v);
for_each(last, v.end(), [](string_ptr &a){
delete a; //if I comment this line everything works "fine"
a = nullptr;
});
v.erase( find(v.begin(), v.end(), nullptr) , v.end() );
print_v(v);
}
为什么这种东西不起作用?如果我用delete
评论该行,一切正常,但我当然有内存泄漏。另一个问题:如果在lambda函数的签名中我使用string*
(而不是typedef string_ptr
)我会得到令人讨厌的编译错误,为什么?
抱歉我的英语不好,我希望问题很清楚。
答案 0 :(得分:1)
问题是你要删除仍然指向有效字符串的元素(在你的情况下,是一个唯一的字符串)。 unique
函数为迭代器提供了刚刚删除的最后一个元素之后的元素。致电unique
后,您将删除最后的所有内容 - &gt;鬻()。这是删除一些在向量的唯一部分中的字符串。这里要清楚的是排序后的输出:
aba 0xca9c20 aba 0xca9d20 aba 0xca9cf0 baba 0xca9c70 laba 0xca9e00 naba 0xca9d50 saba 0xca9cc0 saba 0xca9dd0
致电unique
后:
aba 0xca9c20 baba 0xca9c70 laba 0xca9e00 naba 0xca9d50 saba 0xca9cc0 naba 0xca9d50 saba 0xca9cc0 saba 0xca9dd0
请注意,我已修改print_v
函数以打印字符串的地址。正如您所看到的,字符串 naba 位于内存位置0xca9d50
,在最后一个唯一元素即 saba 之后,重复字符串 naba 与前一个完全相同,即存储在同一地址。因此,当您呼叫delete
时,您也会使第一个字符串的地址无效。因此,当您再次致电print_v
时,它会发现该地址无效并为您提供了段错误。
答案 1 :(得分:1)
如上所述,#product.rb
belongs_to :category
#category.rb
has_many :products
函数基本上使那些放置在返回的迭代器僵尸元素右侧的项目。他们可以访问,但他们没用。这就是您将rake db:migrate
应用于这些项目时无效的原因。
如果您的目标是对特殊项目进行分区,但同时保持其有效性,则您可能希望使用的算法功能为std::stable_partition,使用def change
。因此,代替std::unique
,您可以执行以下操作:
delete
基本上,我们使用std::set
来存储我们最初找到的值。在后续调用lambda函数时,我们通过查询std::unique
函数来检查重复项。如果它返回1,则该项已存在于集合中,否则为0。因此,要将重复的项目放在分区的右侧,我们需要返回#include <algorithm>
#include <set>
//...
std::set<std::string> stringset;
auto last = std::stable_partition(v.begin(), v.end(), [&stringset](const string_ptr& a)
{
if ( stringset.count(*a) ) return false;
stringset.insert(*a); return true;
});
和全新的商品,我们会返回std::set
(如果它是新商品,我们也会将商品添加到商品中)。基本上,我们使用set::count()
编写了false
的非破坏性版本。
因此,这会导致独特的项目不仅被分割到true
的返回迭代器的右侧,这些项目完全有效,可以用于您认为合适的任何目的(在您的情况下,您想要std::unique
他们。)
请注意,此功能正常,如Live Example
所示此外,您可以使用std::stable_partition
,但此功能不会保留项目的相对顺序。您可能希望使用std::stable_partition
,但我假设您要保留元素的顺序。