不将此指针设置为const的构造函数会导致未检测到的问题

时间:2015-08-31 16:38:44

标签: c++ constructor const this-pointer

为了便于阅读,我将课程简化为最低限度:

#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

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

在定义constmessages时,此代码可能会导致一些“问题”(尽管一切正常)。 Message的构造函数不假定const指针的this。因此即使addToFolders是非const函数代码

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

编译好。这里存在一个问题,因为bconst消息,但是复制构造函数将b的地址(通过addToFolders())设置为由{{1}组成的文件夹} set - 低级别Message*丢失了。实际上,如果我要在const中定义一个更改底层消息的函数,我可以更改const消息Folder的{​​{1}},看似没有编译错误。

解决方案是将contents的设置更改为b,但这不允许我通过文件夹(我实际需要)更改邮件。我如何防止创建Folder的const对象,或者甚至更好地强制构造函数中的set<const message*>指针为message,以便this失败?

1 个答案:

答案 0 :(得分:2)

您无法阻止构建const个实例。

如果您在构造函数中使用this,则需要特别小心 - 例如,您可以const_cast明确const *

通常,如果对象的管理未在对象自己的类中处理,则效果会更好。例如,您可以限制事物,以便只能通过folder创建对象,然后folder可以确保正确处理对象。 (这实际上只是关注点分离的一个例子。)