CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 24
  1. #1
    Join Date
    Mar 2009
    Posts
    18

    howto restric a method to being absolutely constant

    Hi,

    I want to be able to declare a restriction in C++ so that a functor object can not change it's state or the state of any object it has a reference to upon calling the functor. This would have to be something like an "absolute const" object. At the same time I would like to be able to pass arguments upon calling the function object who's state it can change.

    I need this because these functor objects will be scheduled between threads and I want to make sure that executing them only affects objects from the targeted thread, passed as arguments. This way I can guarantee no concurrency issues will occur.

    something like this:
    Code:
    //instances on thread 1
    class TargetedFunctor 
    {
    public:
        TargetedFunctor(...);
        virtual void operator(Target &target) absolute_const;
    };
    // At some point thread 1 calls
    x.scheduleFunctor(f, 42);
    
    //instances on thread 2
    class Queue{
    public:
        // threadsafe method
        void scheduleFunctor(absolute_const TargetedFuntor &f, Time when){
            ...
        }
    };
    //At time "when" thread 2 calls
    f(target);
    I fear that C++ supports no such restrictions. If so, does anyone know any C++ extensions or any other languages that do?

  2. #2
    Join Date
    Aug 2005
    Location
    San Diego, CA
    Posts
    1,054

    Lightbulb Re: howto restric a method to being absolutely constant

    I don't understand the question. Doesn't every thread have its own instance of the functor that is completely different from every other instance that was created by other threads? If all the instances do not have any way of gaining access to each other what is the problem?

    if you want a functor to be "read-only" make its operator(), function arguments, and any other private members const and the compiler will ensure that you aren't modifying anything. If you build all of your functions to be const correct there shouldn't be any problems with getting the desired behavior. Do you know about the const qualifier in C++?

    Code:
    bool FooClass::readOnlyFunction(const XType& xParam) const
    {
       // do something with xParam but can't modify it.
       // also this function can't call non-const members of other objects
       bool something(false);
       // you can modify the something variable to indicate something
       return something.
    }

  3. #3
    Join Date
    Jan 2008
    Location
    California, USA
    Posts
    822

    Re: howto restric a method to being absolutely constant

    Quote Originally Posted by kempofighter View Post
    if you want a functor to be "read-only" make its operator(), function arguments, and any other private members const and the compiler will ensure that you aren't modifying anything.
    I think what OP wants is something similar to
    Code:
        void operator()(const Target& obj) const
    where the const in red won't get caught by the compiler if any modification is done on the argument.
    (which I totally agree with you that it doesn't make sense)

    @ssouffri
    AFAIK, there's no such thing as "absolute const" for you can a) cast it away,
    b) make certain members mutable.
    I don't know much about pthread or boost thread functions,
    but for win32 api,
    even if you some how make the method "absolute const",
    the chance is that you will likely pass object as the argument,
    in which case data passed to the thread function
    Code:
        void operator()(const Target& obj) const
        {
            tHandle = (HANDLE)_beginthreadex(NULL, 0, &obj.dispatch, &obj, 0, &tID);
        }
    would require, some type of conversion,
    of which, the conversion is impractical to pursue or non-thread safe.

    I think you have to rely on the design more,
    and implement necessary synchronization.

  4. #4

    Re: howto restric a method to being absolutely constant

    Quote Originally Posted by ssouffri View Post
    Hi,

    I want to be able to declare a restriction in C++ so that a functor object can not change it's state or the state of any object it has a reference to upon calling the functor. This would have to be something like an "absolute const" object.
    That's pretty much just 'regular const'. Just have any references to these objects be const to achieve this part.

    The problem is it's either const or not unless you cast it away or declare it mutable, but this destroys any very thin illusion that const actually restricts anything in the first place. You could protect and unprotect memory to cause it to error out but it would be a huge waste of time for no gain.

  5. #5
    Join Date
    Mar 2009
    Posts
    18

    Re: howto restric a method to being absolutely constant

    I know const can be overridden in more than one way but using const is at least a very strong reminder that an object should only be read. The main problem I have with a plain const method is that it can still change the state of objects its class has a pointer to. I would like an "absolute_const" keyword to declare that a method can only access pointers as if they were declared as pointers to constant objects ( const TYPE *p; ). So basically an absolute_const method could only change the state of its arguments.

    First notice that
    Code:
    virtual void operator(Target &target) absolute_const;
    in my class TargetedFunctor is a virtual function so it's behaviour is undefined for thread 2 that is going to process the functor at some time in the future.

    The main problem I'm concerned about is that some class D, derived from my class TargetedFunctor, can have a pointer to some object X and can write to X in "operator()", called by thread 2, when it is concurrently being accessed by thread 1. Or that it could pass a pointer to "target" on to object X and that "target", from that point on, can also get accessed by thread 1.

    If operator() was declared to be "absolutely_const" then it could not do this. It could only read from objects is has a reference to and write to argument target. Unless it was dowcasted or some things were declared as mutable .

    So does absolute_const exist or can I construct something that is just as restrictive?

    One alternative I thought of was to template the use of TargetedFunctor and then let my "template<F> Queue" class instantiate functors of type F. However I would need to be able to provide an argument object for the construction. And this argument object could very well contain pointers. So this doesn't work unless I can declare that this argument can't contain any pointers which, I think, is also impossible in C++.

    Code:
    template<F, FA>
    class Queue{
    public:
        void scheduleFunctor(FA argument, Time when){
            F f = F(argument);
            ....
        }
    };
    I hope this clarifies my problem.

  6. #6
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: howto restric a method to being absolutely constant

    I did read something somewhere about coopting the "volatile" keyword to serve more or less this purpose. I can't say I'd recommend that, though.

    Perhaps you should think about whether you really need those pointers and references to be non-const *some* of the time. It might be better to have two different classes, one in which they're const and one in which they're not. It would, of course, be impossible to convert safely from the const version to the non-const version; but the other direction should be trivial.

  7. #7
    Join Date
    Aug 2005
    Location
    San Diego, CA
    Posts
    1,054

    Lightbulb Re: howto restric a method to being absolutely constant

    Quote Originally Posted by ssouffri View Post
    I know const can be overridden in more than one way but using const is at least a very strong reminder that an object should only be read. The main problem I have with a plain const method is that it can still change the state of objects its class has a pointer to. I would like an "absolute_const" keyword to declare that a method can only access pointers as if they were declared as pointers to constant objects ( const TYPE *p; ). So basically an absolute_const method could only change the state of its arguments.

    First notice that
    Code:
    virtual void operator(Target &target) absolute_const;
    in my class TargetedFunctor is a virtual function so it's behaviour is undefined for thread 2 that is going to process the functor at some time in the future.

    The main problem I'm concerned about is that some class D, derived from my class TargetedFunctor, can have a pointer to some object X and can write to X in "operator()", called by thread 2, when it is concurrently being accessed by thread 1. Or that it could pass a pointer to "target" on to object X and that "target", from that point on, can also get accessed by thread 1.

    If operator() was declared to be "absolutely_const" then it could not do this. It could only read from objects is has a reference to and write to argument target. Unless it was dowcasted or some things were declared as mutable .

    So does absolute_const exist or can I construct something that is just as restrictive?

    One alternative I thought of was to template the use of TargetedFunctor and then let my "template<F> Queue" class instantiate functors of type F. However I would need to be able to provide an argument object for the construction. And this argument object could very well contain pointers. So this doesn't work unless I can declare that this argument can't contain any pointers which, I think, is also impossible in C++.

    Code:
    template<F, FA>
    class Queue{
    public:
        void scheduleFunctor(FA argument, Time when){
            F f = F(argument);
            ....
        }
    };
    I hope this clarifies my problem.
    First of all const and thread syncronization are two different things. If you have two threads accessing the same functor object then you have a thread synch issue which has nothing to do with const correctness.

    Secondly you CAN make a function that is not able to modify what it points to I think. As I pointed out before make the function itself const. A const function can not call non-const functions or in the case of a class, a const member function cannot modify the state of the object by modifying class attributes. The compiler will flag these problems as errors.

    Code:
    #include <iostream>
    #include <vector>
    #include <algorithm>
    struct SortVectorFunctor
    {
        bool operator()(const std::vector<int>& lhs, const std::vector<int>& rhs) const
        {
    	// compare the last elements of each vector.
    	bool ret(false);
    	if(lhs.size() == rhs.size() && lhs.size() > 0)
    	{
    	    std::vector<int>::size_type last = lhs.size() - 1;
    	    ret = lhs[last] < rhs[last];
    	}
    	
    	return ret;
        }
    };
    
    int sort2dArray()
    {
        const int ROWS(8), COLS(2);
    
        // fill a 2d vector with random values
        std::vector<std::vector<int> > array2D(ROWS, std::vector<int>(COLS));
        for(int row(0); row < ROWS; ++row)
        {
    	for(int col(0); col < COLS; ++col)
    	{
    	    array2D[row][col] = rand() % 100;
    	}
        }
        
        // print before
        for(int row(0); row < ROWS; ++row)
        {
    	for(int col(0); col < COLS; ++col)
    	{
    	    std::cout << array2D[row][col] << ' ';
    	}
    	std::cout << std::endl;
        }
    
        std::sort(array2D.begin(), array2D.end(), SortVectorFunctor());
        
        // print after
        std::cout << std::endl;
        for(int row(0); row < ROWS; ++row)
        {
    	for(int col(0); col < COLS; ++col)
    	{
    	    std::cout << array2D[row][col] << ' ';
    	}
    	std::cout << std::endl;
        }
        return 0;
    }
    
    int main()
    {
        sort2dArray();
        return 0;
    }

  8. #8
    Join Date
    Aug 2005
    Location
    San Diego, CA
    Posts
    1,054

    Lightbulb Re: howto restric a method to being absolutely constant

    Quote Originally Posted by ssouffri View Post
    I know const can be overridden in more than one way but using const is at least a very strong reminder that an object should only be read. The main problem I have with a plain const method is that it can still change the state of objects its class has a pointer to. I would like an "absolute_const" keyword to declare that a method can only access pointers as if they were declared as pointers to constant objects ( const TYPE *p; ). So basically an absolute_const method could only change the state of its arguments.
    I disagree with your assertion completely. A const member function cannot change the state of objects that it has a pointer to even if the pointer is non-const (at least not without some hacking).

    In this slightly modified example you can see that the const functor cannot call non-const functions on members of the class instance. It's not necessary to limit the functor to only use const* attributes. It makes no difference whether the pointer is const or not because the caller is const. Therefore, the caller cannot use a pointer to make function calls unless the function itself is declared as const. Therefore you are still adequately protected in my opinion.

    Code:
    class ValueCollector
    {
    public:
        void insert(int val)
        {
    	values.push_back(val);
        }
        
    private:
        std::vector<int> values;
    };
    
    struct SortVectorFunctor
    {
        SortVectorFunctor()
        {
    	theCollectorPtr = new ValueCollector;
        }
        ~SortVectorFunctor()
        {
    	delete theCollectorPtr;
        }
        
        bool operator()(const std::vector<int>& lhs, const std::vector<int>& rhs) const
        {
    	// compare the last elements of each vector.
    	bool ret(false);
    	if(lhs.size() == rhs.size() && lhs.size() > 0)
    	{
    	    std::vector<int>::size_type last = lhs.size() - 1;
    	    ret = lhs[last] < rhs[last];
    	    
    	    if(ret)
    	    {
    		theCollector.insert(rhs[last]);
    		theCollectorPtr->insert(rhs[last]);
    	    }
    	}
    	
    	return ret;
        }
        ValueCollector theCollector;
        ValueCollector* theCollectorPtr;
        
    };

    Quote Originally Posted by ssouffri View Post
    So basically an absolute_const method could only change the state of its arguments.
    Well if the absolute_const function can change anything than it isn't absolute_const is it? I don't really understand what you mean by its arguments. If the arguments are passed by value or by non-const ref or pointer, it can change them because they aren't const. On the other hand a const member function can not alter the state of the object it belongs to. Is that a problem for you? What did you mean by arguments? I think that you can do exactly what you want using the const qualifier. A const function can call non-const functions on input arguments if the input arguments aren't const. If a const function receives a non-const array as an input it can modify the input array but cannot modify the state of the object that it belongs to. Understand?
    Last edited by kempofighter; November 10th, 2009 at 01:47 PM.

  9. #9
    Join Date
    Oct 2008
    Posts
    1,456

    Re: howto restric a method to being absolutely constant

    Quote Originally Posted by kempofighter
    A const member function cannot change the state of objects that it has a pointer to even if the pointer is non-const (at least not without some hacking).
    uhm.., maybe the OP means a situation like

    Code:
    struct A
    {
    	A(): p_(&i_) {}
    
    	void f() const
    	{
    		*p_ = 3;
    	}
    
    	int  i_;
    	int* p_;
    };
    
    int main()
    {
    	A a;
    
    	a.f();
    }
    and his "absolute_const" qualifier would be equivalent to putting p_ --> (const int*)p_ in the qualified absolute const function...
    Last edited by superbonzo; November 11th, 2009 at 05:23 AM.

  10. #10
    Join Date
    Mar 2009
    Posts
    18

    Exclamation Re: howto restric a method to being absolutely constant

    Quote Originally Posted by kempofighter View Post
    I disagree with your assertion completely. A const member function cannot change the state of objects that it has a pointer to even if the pointer is non-const (at least not without some hacking).
    I wish you were right but the code below compiles without errors or warnings.

    Code:
    class NotConstObject {
    private:
            int i;
    public:
            void nonConstMember(){
                    i=0;
            }
    };
    
    class ConstObject{
    private:
            NotConstObject *nco;
    public:
            ConstObject(NotConstObject *nco): nco(nco){
            }
    
            void operator()() const {
                    nco->nonConstMember();
            }
    };
    
    
    main(void){
     NotConstObject nco;
     const ConstObject o(&nco);
     o();
     return 0;
    }
    The reason why your code fails is because of the following line where a class attribute is changed.
    Code:
    theCollector.insert(rhs[last]);
    Quote Originally Posted by kempofighter View Post
    A const function can call non-const functions on input arguments if the input arguments aren't const. If a const function receives a non-const array as an input it can modify the input array but cannot modify the state of the object that it belongs to. Understand?
    Yes i do but that's not my problem. My problem is simply that
    Code:
    nco->nonConstMember();
    does not cause any compiler errors.

    My compiler is "g++ (SUSE Linux) 4.3.2 [gcc-4_3-branch revision 141291]". Maybe your compiler will refuse to compile the above code in which case it's an interpretation difference issue. If so, which compiler complies with which C++ standard? And which one makes more sense?

  11. #11
    Join Date
    Oct 2008
    Posts
    1,456

    Re: howto restric a method to being absolutely constant

    Quote Originally Posted by ssouffri View Post
    My problem is simply that
    Code:
    nco->nonConstMember();
    does not cause any compiler errors.
    that's because nco "has" type "NotConstObject* const" in your const operator() while you'd need "NotConstObject const*" in order to get compiler errors.

    the only way I see is to wrap your pointers/references in a class exposing const and non const accessors; something like

    Code:
    template <typename T>
    class pseudo_const_ptr
    {
    	T* ptr_;
    
    public:
    	pseudo_const_ptr(T& ref): ptr_(&ref) {}
    
    	const T& operator*() const { return *ptr_; }
    	T& operator*() { return *ptr_; }
    };
    
    struct A
    {
    	A(): p_(i_) {}
    
    	void f() const
    	{
    		*p_ = 3; // now this won't compile...
    	}
    
    	void g()
    	{
    		*p_ = 3; // ...and this is ok
    	}
    
    	pseudo_const_ptr<int> p_;
    	int  i_;
    };
    
    int main()
    {
    	A a;
    
    	a.f();
    	a.g();
    }

  12. #12
    Join Date
    Aug 2005
    Location
    San Diego, CA
    Posts
    1,054

    Re: howto restric a method to being absolutely constant

    Quote Originally Posted by ssouffri View Post
    I wish you were right but the code below compiles without errors or warnings.

    Code:
    class NotConstObject {
    private:
            int i;
    public:
            void nonConstMember(){
                    i=0;
            }
    };
    
    class ConstObject{
    private:
            NotConstObject *nco;
    public:
            ConstObject(NotConstObject *nco): nco(nco){
            }
    
            void operator()() const {
                    nco->nonConstMember();
            }
    };
    
    
    main(void){
     NotConstObject nco;
     const ConstObject o(&nco);
     o();
     return 0;
    }
    The reason why your code fails is because of the following line where a class attribute is changed.
    Code:
    theCollector.insert(rhs[last]);


    Yes i do but that's not my problem. My problem is simply that
    Code:
    nco->nonConstMember();
    does not cause any compiler errors.

    My compiler is "g++ (SUSE Linux) 4.3.2 [gcc-4_3-branch revision 141291]". Maybe your compiler will refuse to compile the above code in which case it's an interpretation difference issue. If so, which compiler complies with which C++ standard? And which one makes more sense?
    Well good point. I never realized that and now I see what you are saying. The issue has to do with pointers. It seems like a security problem to me. I wonder if there is documentation from the stds committee on this because it seems like a serious security problem with the language design, not that I really have time to go find it and read it. That's a really annoying issue. We should have been posting these types of examples in the beginning in order to clarify the problem. This has nothing to do with threading but is really more of a stds question regarding the limitation of const member functions.

  13. #13
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: howto restric a method to being absolutely constant

    ^It's essentially the same issue which prevents you from converting a T** to a const T**.

    I think the question you need to be asking is why you want a single object to have both const and non-const access to a given pointer. It would really make more sense from a safety perspective to only have one or the other from a given type.

    The decorator pattern may provide a means to relate the const and non-const versions of a type effectively.
    Last edited by Lindley; November 11th, 2009 at 12:50 PM.

  14. #14
    Join Date
    Aug 2005
    Location
    San Diego, CA
    Posts
    1,054

    Lightbulb Re: howto restric a method to being absolutely constant

    Anyway, I think that the problem makes perfect sense to me now. The const member function is being allowed to make non-const calls through pointers that belong to the class. I can see where this would seem confusing. The member function doesn't seem like it is truly const. Of course it can modify references/pointers that it receives as arguments (they are not part of the object's state) but why should the const member function be allowed to call non-const functions via a pointer that is a member of the class? I guess you'd have to consider that since we are dealing with a pointer that the thing pointed to is not really part of the class's state. It might be a shared pointer so perhaps that is why the language was not designed to catch this. Now if the member is an object that is owned by the class then it is part of the class's state and therefore cannot be modified by the const member function. Bonzo demonstrated this well with this example where he wrapped the pointer within a class and then instantiated an object as a class attribute.

    Code:
    class foo
    {
          //  the pointer points to something that might not be owned by 
          //  by foo instances.  const member functions can make any call
          // via this pointer.  Is that a security issue or just a misunderstanding
          // about the purpose of a const member function?
          ObjectType* memberPtr;
    
          // This object is owned by each foo instance.  It cannot be modified
          // by const member functions nor can any non-const function be called
          // by non-const member functions
          ObjectType memberPtr;
          
    };
    I think that the OP wants the complier to ensure that a const member function cannot call non-const functions on memberPtr or use memberPtr to modify any attributes of what memberPtr points to. On the other hand, input arguments received by any member function have nothing to do with the class's state (they are part of the callers state). Whether they can be modified depends only on the declaration of the argument and not the const/non-const declaration of the member function itself.

    I think that Bonzo's example is an excellent work around for what could be perceived to be a security flaw by some.

  15. #15
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: howto restric a method to being absolutely constant

    The basic issue is that for a pointer to be constant only means it cannot be redirected at any other address. It does not impose any limitation upon the type it points at.

Page 1 of 2 12 LastLast

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured