Re: Share .cpp and .h along projects
On Wed, 29 Aug 2007 09:19:14 -0500, "Ben Voigt [C++ MVP]"
<rbv@nospam.nospam> wrote:
"Doug Harrison [MVP]" <dsh@mvps.org> wrote in message
news:va49d3hm62f07nrid2oifl9md3fi0kb955@4ax.com...
On Tue, 28 Aug 2007 12:38:48 -0500, "Ben Voigt [C++ MVP]"
<rbv@nospam.nospam> wrote:
It's "volatile-correctness" and prevents the object from being passed
someplace it shouldn't, just like const-correctness does:
class Example
{
char myarray[1000];
void doit() const
{
sprintf(myarray, "%d", 5);
}
};
Because myarray is a pointer-to-const inside a const member function
the compiler stops me from using it as the first argument to sprintf,
overwriting the data and breaking the "const" contract.
To be faithful to what you have been claiming, you should have used a
pointer, not an array. The "corrected" version of your example uses a
volatile pointer, not a pointer-to-volatile:
std::vector* volatile g_sharedVector;
This is perfectly fine:
std::vector* p = g_sharedVector;
Doesn't give you much "protection".
There's a guarantee that the actual value of g_sharedVector will be used,
not a cached value. But if you read what I said, it was that
(&g_sharedVector) could not be passed to a function not designed for
volatile access.
Oh, I understood perfectly, but I am struggling to think of even one
function you could reasonably be worried about. To add to what I said last
time, this is also perfectly fine:
std::vector* p = whatever;
g_sharedVector = p;
You're worried about passing &g_sharedVector to some hypothetical functions
which might assign to it through a non-volatile lvalue, yet you're not even
protecting it against simple assignment, and simple assignment is
incompatible with your InterlockedXXX usage.
Also, you've never once mentioned the vector whose address is used to
initialize g_sharedVector. You need to avoid using that object outside the
critical section. The same situation exists when using a mutex, but if you
use a mutex, you don't need g_sharedVector, you don't have to worry about
your method's unbounded busy-waiting, you don't have to use an extra local
variable and a loop to enter the critical section, you're more portable,
and so forth.
Your notion of "volatile-correctness", which you mentioned last time, is
nowhere near as strong as what Andrei A was proposing several years ago,
and his idea hasn't exactly caught on. At least he was concerned with using
volatile to protect the object, i.e. the elusive vector in your example, to
help prevent its use outside the critical section. Your idea of
"volatile-correctness" merely protects a pointer which doesn't even exist
when using normal synchronization techniques, such as the mutexes I've been
talking about. It doesn't prevent you from assigning g_sharedVector's value
to a non-volatile pointer, nor does it prevent calling vector member
functions through g_sharedVector itself. It doesn't even prevent you from
directly assigning a new value to g_sharedVector. In summary, it provides
unnecessary, useless, false "protection" for something that shouldn't even
exist in the first place.
The release part of the operation was able to use a volatile write in VC2005
and avoid the function call. That wouldn't be correct without volatile.
The "release" part of the operation (on those platforms where it actually
has meaning) occurs due to using the InterlockedXXX API. It is not
necessary for *you* to declare *your* pointer volatile.
--
Doug Harrison
Visual C++ MVP