62

我有以下与迭代使用定义的字符串关联数组有关的问题std::map

-- snip --
class something 
{
//...
   private:
      std::map<std::string, std::string> table;
//...
}

在构造函数中,我使用与字符串数据关联的字符串键对填充表。在其他地方我有一个方法toString,它返回一个字符串对象,该对象包含表对象中包含的所有键和关联数据(作为键=数据格式)。

std::string something::toString() 
{
        std::map<std::string, std::string>::iterator iter;
        std::string* strToReturn = new std::string("");

        for (iter = table.begin(); iter != table.end(); iter++) {
           strToReturn->append(iter->first());
           strToReturn->append('=');
           strToRetunr->append(iter->second());
           //....
        }
       //...
}

当我尝试编译时,出现以下错误:

error: "error: no match for call to ‘(std::basic_string<char,
    std::char_traits<char>, std::allocator<char> >) ()’".

有人可以向我解释缺少什么,我做错了什么吗?hash_map在用户必须定义​​散列函数才能hash_mapstd::string对象一起使用的情况下,我只发现了一些关于类似问题的讨论。在我的情况下也可能是类似的东西吗?

4

8 回答 8

74

您的主要问题是您正在调用first()迭代器中调用的方法。您要做的是使用名为的属性first

...append(iter->first) rather than ...append(iter->first())

作为风格问题,您不应该使用new来创建该字符串。

std::string something::toString() 
{
        std::map<std::string, std::string>::iterator iter;
        std::string strToReturn; //This is no longer on the heap

        for (iter = table.begin(); iter != table.end(); ++iter) {
           strToReturn.append(iter->first); //Not a method call
           strToReturn.append("=");
           strToReturn.append(iter->second);
           //....
           // Make sure you don't modify table here or the iterators will not work as you expect
        }
        //...
        return strToReturn;
}

编辑: facildelembrar 指出(在评论中)在现代 C++ 中你现在可以重写循环

for (auto& item: table) {
    ...
}
于 2009-07-01T00:00:40.657 回答
19
  1. 不要写toString()方法。这不是Java。为您的类实现流运算符。

  2. 更喜欢使用标准算法而不是编写自己的循环。在这种情况下,std::for_each()为您想要做的事情提供一个很好的界面。

  3. 如果您必须使用循环,但不打算更改数据,请首选const_iterator. iterator这样,如果您不小心尝试更改值,编译器会警告您。

然后:

std::ostream& operator<<(std::ostream& str,something const& data)
{
    data.print(str)
    return str;
}

void something::print(std::ostream& str) const
{
    std::for_each(table.begin(),table.end(),PrintData(str));
}

然后当你想打印它时,只需流式传输对象:

int main()
{
    something    bob;
    std::cout << bob;
}

如果您确实需要对象的字符串表示形式,则可以使用lexical_cast.

int main()
{
    something    bob;

    std::string  rope = boost::lexical_cast<std::string>(bob);
}

需要填写的细节。

class somthing
{
    typedef std::map<std::string,std::string>    DataMap;
    struct PrintData
    {
         PrintData(std::ostream& str): m_str(str) {}
         void operator()(DataMap::value_type const& data) const
         {
             m_str << data.first << "=" << data.second << "\n";
         }
         private:  std::ostream& m_str;
    };
    DataMap    table;
    public:
        void something::print(std::ostream& str);
};
于 2009-07-01T00:15:47.600 回答
4

改变你的追加电话说

...append(iter->first)

... append(iter->second)

此外,该行

std::string* strToReturn = new std::string("");

在堆上分配一个字符串。如果您打算实际返回指向此动态分配的字符串的指针,则应将返回值更改为 std::string*。

或者,如果您不想担心在堆上管理该对象,请将本地声明更改为

std::string strToReturn("");

并更改“附加”调用以使用参考语法...

strToReturn.append(...)

代替

strToReturn->append(...)

请注意,这将在堆栈上构造字符串,然后将其复制到返回变量中。这对性能有影响。

于 2009-07-01T00:01:45.820 回答
2

iter->first并且iter->second是变量,您试图将它们称为方法。

于 2009-06-30T23:59:46.917 回答
2

请注意,取消引用 std::map::iterator 的结果是std::pairfirst和的值second不是函数,它们是变量。

改变:

iter->first()

iter->first

同上iter->second

于 2009-07-01T00:02:48.953 回答
1

利用:

std::map<std::string, std::string>::const_iterator

反而:

std::map<std::string, std::string>::iterator
于 2013-04-26T08:51:24.627 回答
0

另一个值得优化的是STL字符串类的c_str ( )成员,它返回一个不可变的以空结尾的字符串,可以作为LPCTSTR传递,例如,传递给需要 LPCTSTR 的自定义函数。虽然我没有通过析构函数来确认它,但我怀疑字符串类会照顾它创建副本的内存。

于 2014-09-07T00:37:43.193 回答
0

在 c++11 中,您可以使用:

for ( auto iter : table ) {
     key=iter->first;
     value=iter->second;
}
于 2014-01-19T00:52:31.843 回答