2015-08-31 79 views
1

切割我的課的最低性能的可讀性:構造函數不是這個指針設置爲const導致漏檢問題

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

此代碼可能會導致一些「問題」 (儘管一切運行正常)定義const版本時messagesMessage的構造函數不會假設this指針的const。因此,即使addToFolders是非const函數的代碼

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

將彙編的罰款。這裏有一個問題,因爲bconst消息,但複製構造函數將b的地址(通過addToFolders())設置爲由set,Message*組成的文件夾 - 低級const丟失。事實上,如果我然後在Folder中定義了一個函數,它改變了底層消息,我可以改變常量消息bcontents,看起來沒有編譯錯誤。

解決方法是將Folder的集合更改爲set<const message*>,但這樣做不允許我通過文件夾更改消息(這實際上是我所希望的)。我如何防止創建message的const對象,或者更好的辦法是強制this指針在構造函數中是const,這樣addToFolders()會失敗?

+1

我無法得到很多的問題。然而,有一點是肯定的 - const永遠不會丟失,除非特別是const_cast。無論你走哪條路都無所謂 - 如果某事被定義爲const,它將保持爲const。 – SergeyA

+1

你說的對象在構建時不是'const'。一旦它的生命週期開始(在構造函數之後),修改一個'const'對象仍然是未定義的行爲。但是,對addToFolders的使用似乎是可疑的 - 特別是因爲你沒有析構函數來重新刪除它。 –

+0

@Alan Stokes我有一個析構函數,我將它添加回去。爲了便於閱讀,我刪除了很多。 – AntiElephant

回答

2

您無法阻止構造const實例。

如果您在構造函數中使用了this,那麼您應該適當小心 - 例如,您可以明確地將其const_cast設置爲const *

通常,如果對象的管理未在對象自己的類中處理,它會更好。例如,您可以限制事物,以便只能通過folder創建對象,然後folder才能確保正確處理它。 (這實際上只是一個關注點分離的例子。)

相關問題