0

So I'm currently developping a so and a dll file to handle the files of my users (basically a filesystem). I have two classes, one is FileData (representing a single file), and a FileList (which as the name suggests is a list of FileDatas). Here is my problem. My code was working, but I needed to implement a sort method based on the metadatas I get on my file and to do that I needed to get my getter to a const method :

I'm compiling with the flags -Wextra -Wall -Werror

FileData.hpp

class FileData
{
 // ...
 std::vector<std::pair<std::string, std::string> > _metadatas;
public:
 FileData(std::string);
 ~FileData();
 FileData(const FileData &);
 std::vector<std::pair<std::string, std::string> > &getMetadatas() const;
};

FileData.cpp (i tried to both return (_metadatas) and (&_metadatas) both fail)

std::vector<std::pair<std::string, std::string> > &FileData::getMetadatas() const
 {
   return (_metadatas);
 }

And here is the error message :

 FileData.cpp: In member function ‘std::vector<std::pair<std::basic_string<char>, std::basic_string<char> > >& FileData::getMetadatas() const’:
 FileData.cpp:164:23: error: invalid initialization of reference of type ‘std::vector<std::pair<std::basic_string<char>, std::basic_string<char> > >&’ from expression of type ‘const std::vector<std::pair<std::basic_string<char>, std::basic_string<char> > >’
 return (_metadatas);
                    ^
make: *** [FileData.o] Error 1

And here is the reason in my FileList.cpp i need to get the getMetadatas a const getter (even though i know getters should always be const anyway) :

FileList.cpp

bool                SortMetadata::sortArtist(const FileData &a, const FileData &b)
{
   int i,j;
   std::vector<std::pair<std::string, std::string> > tmp, temp;
   tmp = a.getMetadatas();
   temp = b.getMetadatas();
   std::string first("");
   std::string second("");
   for (i = 0; i < tmp.size(); ++i)
    {
       if (tmp[i].first.compare("artist") == 0)
           first = tmp[i].second;
    }
   for (j = 0; j < temp.size(); ++j)
    {
        if (temp[j].first.compare("artist") == 0)
            second = temp[j].second;
    }
   return (first.compare(second) < 0);
}

Here is the error message i get if i don't make my getMetadatas() a const method :

 FileList.cpp: In function ‘bool SortMetadata::sortArtist(const FileData&, const FileData&)’:
 FileList.cpp:91:26: error: passing ‘const FileData’ as ‘this’ argument of ‘std::vector<std::pair<std::basic_string<char>, std::basic_string<char> > >&  FileData::getMetadatas()’ discards qualifiers [-fpermissive]
 tmp = a.getMetadatas();
                      ^
 FileList.cpp:92:27: error: passing ‘const FileData’ as ‘this’ argument of ‘std::vector<std::pair<std::basic_string<char>, std::basic_string<char> > >& FileData::getMetadatas()’ discards qualifiers [-fpermissive]
 temp = b.getMetadatas();

I'm not sure what's the problem here, since the code was working fine before I changed my getter to const, and I don't understand what it changes to be const, since the method is just a return.. Thanks for the help guys !

1 Answers1

0
  1. You cannot return a reference to non-const member from a const getter1. You can have two overloads though (const and non-const):

    std::vector<std::pair<std::string, std::string> > &      getMetadatas();
    std::vector<std::pair<std::string, std::string> > const& getMetadatas() const;
    

    But I think you don't even want the first overload and you just forgot one const in the return type.

  2. As @M.M noticed, you don't use address-of operator when returning a reference:

    return _metadatas;
    

(1) It's because you'd violate const-correctness with the following code if that was possible:

const FileData fd;
fd.getMetadatas() = {}; // you're modifying a const object
LogicStuff
  • 19,397
  • 6
  • 54
  • 74
  • I tried to return a const reference as you both suggest, but I can't figure how I should be calling such a function. Because something like : std::vector > meta; meta = test.getMetadatas(); Just won't work .. What am I doing wrong ? – Guillaume Roche-Bayard Dec 25 '15 at 23:17
  • So if I get this straight, there is no way for me to get the metadata vector from a FileData unless this vector is const ? The error is undefined reference to getMetadatas() in main. (Includes are fine). – Guillaume Roche-Bayard Dec 25 '15 at 23:21
  • NO, it is very easy to do (and I'm showing you how). The error is because when I changed the `getMetadas` signature I was expecting you to also change the one of the function definition. You forgot to. – LogicStuff Dec 25 '15 at 23:24
  • I did it on both the .hpp and .cpp of my FileData, the compiler says the error is on main.cpp, do you want me to edit the question with the changes ? – Guillaume Roche-Bayard Dec 25 '15 at 23:26
  • In case you have two overloads declared, you have to have two definitions for them, right? But as I said, you could just have the `const` overload. – LogicStuff Dec 25 '15 at 23:27
  • I removed the non-const definition as you suggested to me ! – Guillaume Roche-Bayard Dec 25 '15 at 23:28
  • main.cpp:(.text+0x338): undefined reference to `FileData::getMetadatas()' – Guillaume Roche-Bayard Dec 25 '15 at 23:31
  • There should definitely not be `return &...`. Either your definition/declaration still doesn't match (it does in your question), you're not recompile and relink the files properly. – LogicStuff Dec 25 '15 at 23:34
  • Ok i changed my code from two lines to a single one (declaration and affectation at the same time), and it works fine now ! Thanks for the help, even though i don't know why writting it on two lines wasn't working ! – Guillaume Roche-Bayard Dec 25 '15 at 23:35