0
votes

I am trying to create a basic application which is modeling "sticky notes" activity. This would contain functions to add notes and delete notes. Below is the code. In deleteNote function, I am finding the title in the vector of Notes which is given as an input argument using std::find method. The std::find API is throwing compilation errors. Below is the code.

#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 >; _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 >; _Predicate = __gnu_cxx::__ops::_Iter_equals_val]’ /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 >; _Predicate = __gnu_cxx::__ops::_Iter_equals_val]’ /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 >; _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 argument 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
This part of the error messages seems to be the most relevant: "error: no match for ‘operator==’ (operand types are ‘Note’ and ‘const Note’)" In short, you have no way to compare two Note objects for equalitySome programmer dude

1 Answers

1
votes

In

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

std::find algorithm tries to compare an element from m_notes with x, but you didn't provide operator== which does it, hence error message. Becuase you are erasing elements based on title, you can write:

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);
    }
    //...
};

then the code compiles, but probably it will crash. You are using range-based for loop which checks vector::end iterator but it may be invalidated when vector::erase is called. See how range-for is implemented and how end is used.

Now you are iterating over all elements in vector and if title matches to title you are calling find to find element to be removed. It is overkill, you can go over vector with iterator and when title is matched just call erase algorithm for the current iterator without re-iterating vector by find:

Rewrite deleteNote into something like this:

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;
    }
}

If you want to move rhs.m_tags; in move ctor and move assignment operator you need to cast rhs.m_tags to Rreference - m_tags = std::move(rhs.m_tags);.