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

时间:2015-05-22 20:39:20

标签: c++ arrays new-operator delete-operator

为什么这段代码错了?我是否遗漏了有关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风格的字符串数组并删除它们的一些特定字符串;使用new []创建C样式字符串数组,并使用new创建每个C样式字符串。代码的结果是没有单词被取消,但数组只是被切片。

3 个答案:

答案 0 :(得分:6)

我在所显示的代码中使用new[]delete[]时未发现任何问题。

不,等等。

我看到了lot¹的问题,但您的意图很明确,代码似乎正在按照您的意愿行事。

我注意到的唯一逻辑问题是你通过值传递strings(它是char**并在函数中重新分配它不会影响包含指针的调用者变量)。将签名更改为

void remove_stopwords(char**& strings, int* length)

所以传递引用而不是修复它。

(1)如果可能,使用std::vector<const char *>似乎更合乎逻辑,甚至更好std::vector<std::string>,它将负责所有分配和解除分配。

答案 1 :(得分:2)

  

每个C风格的字符串都是使用new创建的。

我怀疑这是你的问题 - C样式字符串是char 数组,因此您无法使用new轻松创建它们,您需要使用new[]。这意味着您需要使用delete[]

答案 2 :(得分:1)

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