-
November 9th, 2009, 02:58 PM
#1
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?
-
November 9th, 2009, 05:14 PM
#2
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.
}
-
November 9th, 2009, 05:33 PM
#3
Re: howto restric a method to being absolutely constant
Originally Posted by kempofighter
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.
-
November 10th, 2009, 06:05 AM
#4
Re: howto restric a method to being absolutely constant
Originally Posted by ssouffri
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.
-
November 10th, 2009, 11:44 AM
#5
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.
-
November 10th, 2009, 11:55 AM
#6
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.
-
November 10th, 2009, 01:22 PM
#7
Re: howto restric a method to being absolutely constant
Originally Posted by ssouffri
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;
}
-
November 10th, 2009, 01:45 PM
#8
Re: howto restric a method to being absolutely constant
Originally Posted by ssouffri
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;
};
Originally Posted by ssouffri
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.
-
November 11th, 2009, 05:20 AM
#9
Re: howto restric a method to being absolutely constant
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.
-
November 11th, 2009, 12:10 PM
#10
Re: howto restric a method to being absolutely constant
Originally Posted by kempofighter
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]);
Originally Posted by kempofighter
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?
-
November 11th, 2009, 12:30 PM
#11
Re: howto restric a method to being absolutely constant
Originally Posted by ssouffri
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();
}
-
November 11th, 2009, 12:35 PM
#12
Re: howto restric a method to being absolutely constant
Originally Posted by ssouffri
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.
-
November 11th, 2009, 12:47 PM
#13
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.
-
November 11th, 2009, 01:10 PM
#14
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.
-
November 11th, 2009, 01:14 PM
#15
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.
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|