当我遍历 C++ 映射时,为什么它会给我实例化错误?

When I loop through a C++ map, why does it give me an instantiation error?

提问人:joshua 提问时间:8/3/2023 最后编辑:UpAndAdamjoshua 更新时间:8/4/2023 访问量:70

问:

我正在尝试遍历地图,但我尝试的任何方法似乎都不起作用......我声明并定义地图如下:

// loop through the strings and group based on length
map<size_t, NGroup> groups;
for (size_t i = 0; i < strs.size(); i++) {
    size_t len = strs[i].size();
    if (groups.count(len) != 0) {
        groups.at(len).appendString(strs[i]);
    } else {
        NGroup g(strs[i]);
        groups[len] = g;
    }
}

具有以下相关类:

class AnagramGroup {
public:
    map<char, size_t> freqs;
    map<char, size_t> ground;
    vector<string> anagrams;

    AnagramGroup(map<char, size_t> m, string anagram) {
        freqs = m;
        ground = m;
        anagrams.push_back(anagram);
    }
    AnagramGroup(AnagramGroup &other);
};

class NGroup {
public:
    vector<string> strings;
    vector<AnagramGroup> groups;

    NGroup(string str) {
        vector<string> strs = {str};
        strings = strs;
    }
    NGroup(vector<string> strs) {
        strings = strs;
    }
    NGroup(NGroup &other);

    void appendString(string str) {
        strings.push_back(str);
    }
};

我尝试使用此处列出的方法遍历地图:

map<size_t, NGroup>::iterator it;
for (it = groups.begin(); it != groups.end(); it++) {
...
}
for (const auto &p : groups) {
...
}

但我总是遇到同样的错误:

In file included from prog_joined.cpp:1:
In file included from ./precompiled/headers.h:13:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/cmath:1927:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/specfun.h:45:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_algobase.h:64:
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_pair.h:303:17: error: the parameter for this explicitly-defaulted copy constructor is const, but a member or base requires it to be non-const
      constexpr pair(const pair&) = default;
                ^
Line 61: Char 38: note: in instantiation of template class 'std::pair<const unsigned long, NGroup>' requested here
        for (it = groups.begin(); it != groups.end(); it++) {
                                     ^

我错过了什么?

C++ 循环 字典 C++14

评论

0赞 Caleth 8/4/2023
题外话:要么没有做你认为的事情,要么你应该使用strs[i]std::vector<NGroup>

答:

1赞 selbie 8/3/2023 #1

std::map 需要支持以下语义:

NGroup ng& = groups["some key that doesn't exist in this map"];

当键不在映射中时,它默认构造映射的值类型的实例,并将其分配给该键。如果没有默认构造函数,它就不知道要传递给对象的构造函数的内容。

因此,NGroup 需要一个默认构造函数。这为我解决了这个问题:

class NGroup {
public:
    vector<string> strings;
    vector<AnagramGroup> groups;

    NGroup() {  // add this

    }

此外,NGroup 和 AnagramGroup 都不需要复制构造函数,因为默认构造函数将执行正确的操作。因此,您可以同时删除两者。仅当成员变量无法简单复制或依赖成员变量或成员变量自己的复制构造函数时,才需要复制构造函数。

现在,让我们通过将大多数参数作为 const 引用传递来清理代码的其余部分,这样您就不会无意中复制这些字符串和集合。

class AnagramGroup {
public:
    map<char, size_t> freqs;
    map<char, size_t> ground;
    vector<string> anagrams;

    AnagramGroup(const map<char, size_t>& m, const string& anagram) :
        freqs(m), ground(m), anagrams({anagram}) {
    }

};

class NGroup {
public:
    vector<string> strings;
    vector<AnagramGroup> groups;

    NGroup() {

    }

    NGroup(const string& str) : strings({ str }) {
    }

    NGroup(const vector<string>& strs) : strings(strs) {
    }

    void appendString(const string& str) {
        strings.push_back(str);
    }
};

评论

0赞 joshua 8/3/2023
哇,谢谢!单独添加默认构造函数不起作用,但也使用 const 引用参数修复了它!为什么您要将大多数参数作为常量引用传递?我认为 C++ 容器处理复制。您的实现是否仅复制指向容器的引用(指针)?(提前对不起!我来自C背景,所以一些隐藏在我身边的记忆有点令人困惑)
1赞 Miles Budnek 8/3/2023
@joshua 使用引用参数初始化对象会复制引用的对象。因此,例如,将引用的对象复制到对象的成员中。通过引用 const 来接受参数可防止它被不必要地复制第二次(从原始对象复制到函数参数)。NGroup(const vector<string>& strs) : strings(strs) {}strsstrings
0赞 joshua 8/3/2023
Gotcha 这是有道理的,谢谢!如果我想阻止任何复制并将引用的对象移动到对象的成员中,我将如何做到这一点?strsstrings
1赞 sweenish 8/3/2023
首选构造函数,而不是空体。= default
1赞 Miles Budnek 8/3/2023 #2

问题在于,你的“复制构造函数”并不是真正的复制构造函数,因为它们通过引用非常量来接受它们的参数。更改复制构造函数以接受对 const 的引用,或者如果它们所做的只是逐个字段的复制,则将其删除,因为编译器将自动生成执行此操作的复制构造函数。

a 的元素是 s,并且是可复制的。当实例化 的复制构造函数时,编译器将提出如下内容:std::mapstd::pairstd::pairstd::pair<const size_t, NGroup>

pair(const pair& other)
    : first(other.first),
      second(other.second)
{}

但是,由于是对 const 的引用,这意味着它是 . 没有接受 a 作为参数的构造函数,因此实例化无效。otherother.secondconst NGroupNGroupconst NGroupstd::pair

评论

0赞 joshua 8/3/2023
@selbie说我不需要复制构造函数......
1赞 Miles Budnek 8/3/2023
您需要一个,但不需要显式定义一个。就像我说的,如果你的复制构造函数除了逐个字段的复制之外什么都不做,那么编译器默认生成的构造函数将做完全相同的事情,所以你可以省略你的定义。
1赞 joshua 8/3/2023
啊,好吧!我之前收到过一个错误,上面写着,所以我认为解决方案是添加一个复制构造函数。但是我现在看到这表明我缺少默认构造函数。Line 19: Char 5: note: candidate constructor not viable: requires single argument 'strs', but no arguments were provided Line 12: Char 7: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided Line 12: Char 7: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 0 were providedno arguments were provided