Thread: Const question

  1. #1
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654

    Const question

    I just wanted to hear opinions on this.
    There's a function that takes a pointer...
    Code:
    ERROR1 CRegistry::AddIndex(const CIndex* const pIndex, UINT* const pVectorIndex, const bool bLoadingNow)
    ...which it promises that it will in no way change or mess with.
    However, the problem comes later:
    Code:
    vector<CIndex*> m_vIndexes; // Here is where all the indexes are stored
    CTypedPtrMap<CMapWordToPtr, UINT64, CIndex*> m_IndexByID; // Used to find an index by its ID
    
    rHive.m_vIndexes.push_back(pIndex);
    rHive.m_IndexByID.SetAt(pIndex->dwId, pIndex); // Save index in the list to identify it by its ID
    The function needs to save the pIndex is a vector for storage and set it in a map for lookup. Other functions will (and must) be able to modify these pointers, but the function itself will not mess around with pIndex.

    So the question is: should it be feasible to cast away the const before storing it in the map? That way the function can take a const-type pointer, which be const correct since the function won't modify the pointer.
    Last edited by Elysia; 12-01-2007 at 08:18 AM.

  2. #2
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Perhaps mutable is an option.

  3. #3
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    This doesn't seem to work since...
    // pIndex == const CIndex* const pIndex
    // and the vector takes vector<CIndex*> m_vIndexes
    // And gives the compile error error C2664: 'std::vector<_Ty>:: push_back' : cannot convert parameter 1 from 'const CRegistry::CIndex *const ' to 'CRegistry::CIndex *const &'

  4. #4
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I'm not sure I understand why it's doing that. Mutables can only be modified by const functions and for me it is usually a better alternative in the rare event I need to alter a const.

    I will say that using mutable is ugly and I don't normally recommend it because usually it means you need to rethink a design but in this case I would say it would be feasible to use if you could get it to work.

    From http://developer.kde.org/~wheeler/cpp-pitfalls.html
    Code:
    class Foo
    {
    public:
        Foo() : m_object( 0 ) // initalize to null
        {
    
        }
        ~Foo()
        {
            delete m_object;
        }
    
        const Object *object() const
        {
            if( !m_object )
                m_object = new Object;
    
            return m_object;
        }
    
    private:
        mutable Object *m_object;
    };
    If other functions need to modify this I believe they must be const functions.
    Last edited by VirtualAce; 12-01-2007 at 11:15 AM.

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Sure, but we're not talking about a free object here. We're talking about a vector and a map which takes a pointer of type CIndex* and pIndex in the function is const CIndex* const, so basically you'd be throwing away the const.

    Function:
    Code:
    ERROR1 CRegistry::AddIndex(const CIndex* const pIndex, UINT* const pVectorIndex, const bool bLoadingNow) const
    {
    	// Save index in list
    	CHive& rHive = GetHive();
    	rHive.m_vIndexes.push_back(pIndex); // ERROR
    	
    	if (!bLoadingNow) CHECK_IF_ERROR_1( UpdateIndexInfo(pIndex) ); // Update index information in index file
    	rHive.m_IndexByID.SetAt(pIndex->dwId, pIndex); // ERROR
    	pIndexB = NULL;
    
    	if (pVectorIndex) *pVectorIndex = (rHive.m_vIndexes.end() - rHive.m_vIndexes.begin());
    	return ERROR_SUCCESS;
    }
    GetHive() return a CHive as you can see.
    Declaration of CHive:
    Code:
    class CHive
    {
    	friend class CRegistry;
    	mutable vector<CIndex*> m_vIndexes;
    	vector<CIndex*> m_vFreeBlocks;
    	vector<CIndex*> m_vIndexToUpdate;
    	mutable CTypedPtrMap<CMapWordToPtr, UINT64, CIndex*> m_IndexByID;
    	CIndex* pRoot; // The root index item
    	UINT64 nFreeId; // SAVE
    	UINT64 nLastOffset; // SAVE
    };
    Last edited by Elysia; 12-01-2007 at 11:31 AM.

  6. #6
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Code:
    rHive.m_vIndexes.push_back(pIndex); // ERROR
    Code:
    mutable vector<CIndex*> m_vIndexes;
    Code:
    ERROR1 CRegistry::AddIndex(const CIndex* const pIndex,
    I see a problem here. Again I do not use mutable very much at all but if you passed the object as a mutable CIndex* const pIndex perhaps it may work. You would be saying we can modify it but only inside of this function and nowhere else.

    I tried this:
    Code:
    #include "stdafx.h"
    #include <vector>
    
    class Index
    {
    
    
    };
    
    class Hive
    {
        std::vector<Index *> m_vIndexes;
    
    public:
    
        Hive() { }
    
        void Add(mutable Index* const pIndex)
        {
            m_vIndexes.push_back(pIndex);
        }
    
    };
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        Index *pIndex =  new Index();
        Hive *pHive = new Hive();
        
        pHive->Add(pIndex);
    
        delete pHive;
        delete pIndex;
    
        return 0;
    }
    And got this:
    e:\msvc 2005 projects\mutabletest\mutabletest.cpp(21) : warning C4042: 'pIndex' : has bad storage class

    So I don' think that will work.
    Last edited by VirtualAce; 12-01-2007 at 11:51 AM.

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Yeah, so question is: should I take a non-const pointer or cast it to non-const to save it in the map (since the function doesn't modify the pointer, only saves it in the map)?
    EDIT: I believe the problem lies in that std::vector.push_back() isn't const and doesn't take a const object either, so the compiler refuses to call it.
    Last edited by Elysia; 12-01-2007 at 11:46 AM.

  8. #8
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    It will work if you remove the const from in front of CIndex.

    Code:
     void Add(Index* const pIndex)
     {
            m_vIndexes.push_back(pIndex);
    
    }
    This works too:
    Code:
    class Hive
    {
        std::vector<const Index *> m_vIndexes;
    
    public:
    
        Hive() { }
    
        void Add(const Index* const pIndex)
        {
            m_vIndexes.push_back(pIndex);
    
        }
    
    };
    And yet another:
    Code:
    class Hive
    {
        std::vector<mutable Index *> m_vIndexes;
    
    public:
    
        Hive() { }
    
        void Add(Index* const pIndex)
        {
            m_vIndexes.push_back(pIndex);
    
        }
    
    };
    It depends on what you want to do. It is ok with mutable objects in the vector but it is not ok with passing a mutable object to Add().
    Last edited by VirtualAce; 12-01-2007 at 11:59 AM.

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Is that the best solution, though? The function isn't supposed to modify pIndex in any way and works fine with const CIndex* const pIndex.

  10. #10
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I don't know what the best solution is. All of them are farely ugly to me.

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Then I will remove const through a const_cast for now.

  12. #12
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    In which case you should ask yourself is it necessary for the object to be const in the first place? Either way you look at it you are removing the const. The const_cast method is probably the simplest since you can still pass in a const object and then remove it when and only when you need to.

    I don't think any of them are what I would call elegant solutions.
    Last edited by VirtualAce; 12-01-2007 at 12:08 PM.

  13. #13
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    In which case, I will ask another question: is it every necessary for an object to be const? The whole idea of "const correct" is to have the compiler catch bugs for you.
    And I'd rather be fully const correct, than half const correct. If the function isn't going to modify the pointer, then the pointer should be fully const.
    It's an evil act I have to do, since there's no way out of this situation.

  14. #14
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Well your function is not modifying the pointer but push_back obviously is modifying it. So even though you are saying that to the person reading the code that your function does not modify it you are calling a function inside of it that does.

    The good part is you only have to cast away const when you do the push_back. The best time for an object to be const is when it is never modified. If you ever need to modify it later then you should probably ask yourself why it is const. Thankfully you can cast it away for those rare times you may need to when no other elegant solution exists.

    Your saying that the index pointer cannot be modified and yet later you are saying it must be modifed. This is where I'm losing the logic.
    Last edited by VirtualAce; 12-01-2007 at 12:17 PM.

  15. #15
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    That's kind of silly, really.
    push_back isn't const, true, but I don't think it's modifying it, either. It's probably that the function is modifying the class itself (storing the value). However, it takes a type of CIndex* to store, and not const CIndex* const, so the compiler won't allow me.
    I need to store it for later since other functions will modify the pointer, so the vector can't store a const pointer either...

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 8
    Last Post: 04-25-2008, 02:45 PM
  2. Drawing Program
    By Max_Payne in forum C++ Programming
    Replies: 21
    Last Post: 12-21-2007, 05:34 PM
  3. matrix class
    By shuo in forum C++ Programming
    Replies: 2
    Last Post: 07-13-2007, 01:03 AM
  4. Need help implementing a class
    By jk1998 in forum C++ Programming
    Replies: 8
    Last Post: 04-05-2007, 03:13 PM
  5. Replies: 6
    Last Post: 12-06-2005, 09:23 AM