尝试从std :: vector获取用户定义的对象时,出现std :: find的编译错误

时间:2019-03-19 17:31:54

标签: c++11 vector

我正在尝试创建一个对“便签”活动进行建模的基本应用程序。这将包含添加注释和删除注释的功能。下面是代码。在deleteNote函数中,我正在使用std :: find方法作为输入参数给出的Notes向量中找到标题。 std :: find API抛出编译错误。下面是代码。

```#include <iostream>
#include <vector>
#include <utility>
#include <tuple>
#include <algorithm>

using InitializerTags = std::initializer_list<std::string>;
using TupleObject = std::tuple<std::string, std::string, std::string>;
class Note
{

public:
    TupleObject m_tags;

    Note(std::string title, std::string text, std::string tags){
        std::cout<< "parameterized Constructor"<< std::endl;
        m_tags  =  std::make_tuple(title, text, tags);
    }

    /*Note(const Note& rhs){
        std:: cout << "copy constructor"<< std::endl;
        m_tags = rhs.m_tags;
    }*/

    Note(Note&& rhs){
        std::cout<< "move constructor"<< std::endl;
        m_tags = rhs.m_tags;
    }

    Note& operator=(Note&& rhs){
        std::cout << "move assignment"<< std::endl;
        if(this != &rhs){
            m_tags = rhs.m_tags;
        }
        return *this;
    }

    Note() = delete;
    Note(const Note& rhs) = delete;
    Note& operator=(const Note& rhs) = delete;

    ~Note(){

    }
};

class Storyboard
{
private:
    std::vector <Note> m_notes;
public:

    /*Storyboard(){
        m_notes.reserve(1);
    }*/

    void addNote(std::string title, std::string text, std::string tags)
    {
        std::cout << "inside addNote"<< std::endl;
        m_notes.emplace_back(title, text, tags);
    }

    void deleteNote(std::string title)
    {
        for(auto& x: m_notes){
            if(std::get<0>(x.m_tags) == title){
                m_notes.erase(std::find(m_notes.begin(),m_notes.end(), x));
            }
        }
    }


    void print()
    {
        std::cout << "Inside print"<< std::endl;
        for(auto& x : m_notes){
            std::cout << std::get<0>(x.m_tags)<< " ";
            std::cout << std::get<1>(x.m_tags)<< " ";
            std::cout << std::get<2>(x.m_tags)<< " ";
            std::cout << std::endl;
        }
    }
};



Below is the error.

In file included from /usr/include/c++/5/bits/stl_algobase.h:71:0,
                 from /usr/include/c++/5/bits/char_traits.h:39,
                 from /usr/include/c++/5/ios:40,
                 from /usr/include/c++/5/ostream:38,
                 from /usr/include/c++/5/iostream:39,
                 from StoryBoard.cpp:1:
/usr/include/c++/5/bits/predefined_ops.h: In instantiation of ‘bool __gnu_cxx::__ops::_Iter_equals_val<_Value>::operator()(_Iterator) [with _Iterator = __gnu_cxx::__normal_iterator<Note*, std::vector<Note> >; _Value = const Note]’:
/usr/include/c++/5/bits/stl_algo.h:120:14:   required from ‘_RandomAccessIterator std::__find_if(_RandomAccessIterator, _RandomAccessIterator, _Predicate, std::random_access_iterator_tag) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Note*, std::vector<Note> >; _Predicate = __gnu_cxx::__ops::_Iter_equals_val<const Note>]’
/usr/include/c++/5/bits/stl_algo.h:161:23:   required from ‘_Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [with _Iterator = __gnu_cxx::__normal_iterator<Note*, std::vector<Note> >; _Predicate = __gnu_cxx::__ops::_Iter_equals_val<const Note>]’
/usr/include/c++/5/bits/stl_algo.h:3790:28:   required from ‘_IIter std::find(_IIter, _IIter, const _Tp&) [with _IIter = __gnu_cxx::__normal_iterator<Note*, std::vector<Note> >; _Tp = Note]’
StoryBoard.cpp:67:73:   required from here
/usr/include/c++/5/bits/predefined_ops.h:194:17: error: no match for ‘operator==’ (operand types are ‘Note’ and ‘const Note’)
  { return *__it == _M_value; }


I Checked the files in which the error occurred. 
The problem has occurred with the signature of std::find which is 
std::find(_IIter, _IIter, const _Tp&)

The 3rd input arguement is being taken as **const reference** and this is being compared with non const reference in predefined_ops.h:194.

I am trying to understand what in my code led to this situation.
Also trying to figure out the fix.
Any help which would clear my understanding would be appreciated.

1 个答案:

答案 0 :(得分:0)

std::find(m_notes.begin(),m_notes.end(), x)

std::find算法尝试将m_notes中的元素与x进行比较,但是您没有提供执行该操作的operator==,因此会出现错误消息。因为您要删除基于标题的元素,所以可以这样写:

class Note
{
public:
    //...

    // comparison operator as member function
    bool operator == (const Note& theOther) const {
        // compare titles
        return std::get<0>(m_tags) == std::get<0>(theOther.m_tags);
    }
    //...
};

然后编译代码,但是可能会崩溃。 您正在使用基于范围的for循环来检查vector::end迭代器,但是在调用vector::erase时可能无效。 See how range-for is implemented and how end is used.

现在,您要遍历vector中的所有元素,如果标题与title相匹配,则您正在调用find来查找要删除的元素。实在是太过分了,您可以使用迭代器遍历vector,而当标题匹配时,只需为当前迭代器调用erase算法,而无需通过find重新迭代vector:

deleteNote重写为如下内容:

void deleteNote(std::string title)
{
    for (auto it = m_notes.begin(); it != m_notes.end(); )
    {
        if(std::get<0>(it->m_tags) == title)
            it = m_notes.erase(it); // returns the first element past the removed one
        else 
            ++it;
    }
}

如果要在移动ctor和移动赋值运算符中移动rhs.m_tags;,则需要将 rhs.m_tags 强制转换为Rreference-m_tags = std::move(rhs.m_tags);