Search code examples
c++constructorconstantsthis-pointer

Constructors not setting this pointer to const causes undetected issues


Cutting my classes to the bare-minimum for readability:

#ifndef MESSAGEFOLDER
#define MESSAGEFOLDER

#include <string>
#include <set>

class Message;

class Folder{
public: 
    void addMsg(Message* m) { messages.insert(m); } 
    ~Folder() { removeFromMessages(); }
private:
    std::set<Message*> messages;
    void removeFromMessages(); //removes its pointers from Messages
};

class Message{
    friend class Folder;
public:
    Message(const std::string &s = ""): contents(s) { }
    Message(const Message& rhs): contents(rhs.contents), folders(rhs.folders) { addToFolders(); }
    Message& save(Folder&); 
    ~Message() { removeFromFolders(); }
private:
    std::string contents;
    std::set<Folder*> folders;
    void addToFolders();
    void removeFromFolders(); //removes its pointers from Folders
};


#endif // MESSAGEFOLDER

In MessageFolder.cpp

void Message::addToFolders(){
    for(const auto& f : folders)
        f->addMsg(this);
}

Message& Message::save(Folder& f){
    folders.insert(&f);
    f.addMsg(this);
    return *this;
}

This code could cause some "problems" (albeit everything runs fine) when defining const versions of messages. The constructors for Message do not assume const of the this pointer. So even though addToFolders is a non-const function the code

Message a("hello");
Folder f;
a.save(f);
const Message b(a);

would compile fine. There is an issue here because b is a const message but the copy-constructor sets b's address (through addToFolders()) to a Folder consisting of a set of Message* - the low-level const is lost. Indeed if I were to then define a function in Folder which changed the underlying messages I could change the contents of the const Message b seemingly with no compile error.

A solution would be to change the Folder's set to set<const message*> but this disallows me to change messages through the folders (which I do actually desire). How would I prevent const objects of message being created or, even better, force that the this pointer in the constructors is const so that addToFolders() would fail?


Solution

  • You can't prevent const instances being constructed.

    If you use this in your constructor it is up to you to be suitably careful - you can explicitly const_cast it to a const *, for example.

    Generally it works better if the management of the object is not handled within the object's own class. For example, you could restrict things so that the object can only be created via a folder, and the folder can then ensure it is handled correctly. (This is really just an example of separation of concerns.)