delete 和 delete[] 的确切行为是什么?
What is the exact behaviour of delete and delete[]?
为什么这段代码是错误的?关于 delete
和 delete[]
的行为,我是否遗漏了什么?
void remove_stopwords(char** strings, int* length)
{
char** strings_new = new char*[*length];
int length_new = 0;
for(int i=0; i<*length; i++) {
if(is_common_keyword(strings[i]) == 0) {
strings_new[length_new] = strings[i];
length_new++;
}
else {
delete strings[i];
strings[i] = nullptr;
}
}
delete[] strings;
strings = new char*[length_new];
for(int i=0; i<length_new; i++) {
strings[i] = strings_new[i];
}
delete[] strings_new;
*length = length_new;
}
说明:此代码应采用 C 风格字符串数组并删除其中的一些特定字符串; C 风格字符串数组是使用 new[] 创建的,每个 C 风格字符串都是使用 new 创建的。代码的结果是没有单词被取消,只是对数组进行了切片。
every C-style string was created using new.
我怀疑这是你的问题 -- C 风格的字符串是 char
数组 ,所以你不能轻易地用 new
创建它们,你需要使用 new[]
。这意味着您需要使用 delete[]
.
我没有发现在显示的代码中使用 new[]
或 delete[]
有任何问题。
不,等等。
我看到 很多¹ 问题,但您的意图很明确,代码似乎在做您想要它做的事情。
我注意到的唯一逻辑问题是您按值传递 strings
(它是 char**
并且在函数中重新分配它不会影响包含指针的调用者变量)。将签名更改为
void remove_stopwords(char**& strings, int* length)
所以一个 reference 被传递而不是应该修复它。
(1) 使用 std::vector<const char *>
似乎更合乎逻辑,如果可能的话 std::vector<std::string>
更好,这将处理所有分配和释放。
正如@6502 所指出的,您的基本问题相当简单:您正在传递一个 char **
,并试图在函数中修改它(而不是它指向的内容)。
您将其用作动态分配的字符串数组,因此您修改的只是传递给函数的指针的副本。由于您(显然)希望函数修改传递给它的内容,因此您需要传递 char ***
(呃!)或 char **&
(仍然很糟糕)。
你真的应该为数据使用 vector<std::string>
。至少在我看来,删除停用词的代码应该写成通用算法,大致顺序如下:
template <typename InIt, typename OutIt>
void remove_stop_words(InIt b, InIt e, OutIt d) {
std::remove_copy_if(b, e, d,
[](std:string const &s) { is_stop_word(s); });
}
有了这个,调用代码看起来像这样:
// read input
std::vector<std::string> raw_input { std::istream_iterator<std::string>(infile),
std::istream_iterator<std::string>() };
// Filter out stop words:
std::vector<std::string> filtered_words;
remove_stop_words(raw_input.begin(), raw_input.end(),
std::back_inserter(filtered_words));
但是,在这种情况下,您实际上根本不需要将原始输入词存储到向量中。您可以将 istream_iterator 直接传递给 remove_stop_words
,并让它产生所需的结果:
std::ifstream in("raw_input.txt");
std::vector<std::string> filtered_words;
remove_stop_words(std::istream_iterator<std::string>(in),
std::istream_iterator<std::string>(),
std::back_inserter(filtered_words));
顺便说一句,您也可以考虑改用 Boost filter_iterator。这 would/will 允许您在读取数据时在迭代器中进行过滤,而不是在应用于迭代器的算法中进行过滤。
为什么这段代码是错误的?关于 delete
和 delete[]
的行为,我是否遗漏了什么?
void remove_stopwords(char** strings, int* length)
{
char** strings_new = new char*[*length];
int length_new = 0;
for(int i=0; i<*length; i++) {
if(is_common_keyword(strings[i]) == 0) {
strings_new[length_new] = strings[i];
length_new++;
}
else {
delete strings[i];
strings[i] = nullptr;
}
}
delete[] strings;
strings = new char*[length_new];
for(int i=0; i<length_new; i++) {
strings[i] = strings_new[i];
}
delete[] strings_new;
*length = length_new;
}
说明:此代码应采用 C 风格字符串数组并删除其中的一些特定字符串; C 风格字符串数组是使用 new[] 创建的,每个 C 风格字符串都是使用 new 创建的。代码的结果是没有单词被取消,只是对数组进行了切片。
every C-style string was created using new.
我怀疑这是你的问题 -- C 风格的字符串是 char
数组 ,所以你不能轻易地用 new
创建它们,你需要使用 new[]
。这意味着您需要使用 delete[]
.
我没有发现在显示的代码中使用 new[]
或 delete[]
有任何问题。
不,等等。
我看到 很多¹ 问题,但您的意图很明确,代码似乎在做您想要它做的事情。
我注意到的唯一逻辑问题是您按值传递 strings
(它是 char**
并且在函数中重新分配它不会影响包含指针的调用者变量)。将签名更改为
void remove_stopwords(char**& strings, int* length)
所以一个 reference 被传递而不是应该修复它。
(1) 使用 std::vector<const char *>
似乎更合乎逻辑,如果可能的话 std::vector<std::string>
更好,这将处理所有分配和释放。
正如@6502 所指出的,您的基本问题相当简单:您正在传递一个 char **
,并试图在函数中修改它(而不是它指向的内容)。
您将其用作动态分配的字符串数组,因此您修改的只是传递给函数的指针的副本。由于您(显然)希望函数修改传递给它的内容,因此您需要传递 char ***
(呃!)或 char **&
(仍然很糟糕)。
你真的应该为数据使用 vector<std::string>
。至少在我看来,删除停用词的代码应该写成通用算法,大致顺序如下:
template <typename InIt, typename OutIt>
void remove_stop_words(InIt b, InIt e, OutIt d) {
std::remove_copy_if(b, e, d,
[](std:string const &s) { is_stop_word(s); });
}
有了这个,调用代码看起来像这样:
// read input
std::vector<std::string> raw_input { std::istream_iterator<std::string>(infile),
std::istream_iterator<std::string>() };
// Filter out stop words:
std::vector<std::string> filtered_words;
remove_stop_words(raw_input.begin(), raw_input.end(),
std::back_inserter(filtered_words));
但是,在这种情况下,您实际上根本不需要将原始输入词存储到向量中。您可以将 istream_iterator 直接传递给 remove_stop_words
,并让它产生所需的结果:
std::ifstream in("raw_input.txt");
std::vector<std::string> filtered_words;
remove_stop_words(std::istream_iterator<std::string>(in),
std::istream_iterator<std::string>(),
std::back_inserter(filtered_words));
顺便说一句,您也可以考虑改用 Boost filter_iterator。这 would/will 允许您在读取数据时在迭代器中进行过滤,而不是在应用于迭代器的算法中进行过滤。