delete 和 delete[] 的确切行为是什么?

What is the exact behaviour of delete and delete[]?

为什么这段代码是错误的?关于 deletedelete[] 的行为,我是否遗漏了什么?

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 允许您在读取数据时在迭代器中进行过滤,而不是在应用于迭代器的算法中进行过滤。