Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

code pattern for locking & unlocking

102 views
Skip to first unread message

Daniel Anderson

unread,
Nov 25, 2010, 5:48:37 PM11/25/10
to

Hi!

I often have to acquire locks and release them after I'm finished with
them.
I use constructor/destructor to acquire & release locks. everything
works fine.
sometime I must acquire a lock for few instructions, then release it
in the middle of a big function. I use braces to get timely
destructors, but I find the "middle of nowhere" braces kind of
embarrassing.
something like:

struct Lock
{
Lock(Mutex& mtx) mtx_(mtx) { mtx.lock(); }
~Lock() { mtx_.unlock(); }
operator bool() { return true;}
};

void someFunc()
{
// do some stuff
...
// now time to update share data
{
Lock myLock(data_mutex);
//use locked data
....
} // destructor called
// do more stuff
...
}

I would like to have something like the using keyword in c#.
Is there a way to fake it in C++ ?
for now I'm using an if to do it.


void someFunc()
{
// do some stuff
...
// now time to update share data
if (Lock myLock = Lock(data_mutex))
{
//use locked data
....
} // Unlock done by destructor

// do more stuff
...
}

Is it good programming ?
Is there a better way ?

Thanks

Daniel Anderson


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Daniel Krügler

unread,
Nov 26, 2010, 9:37:27 AM11/26/10
to

Am 25.11.2010 23:48, schrieb Daniel Anderson:
>
> Hi!
>
> I often have to acquire locks and release them after I'm finished with
> them.
> I use constructor/destructor to acquire& release locks. everything
> works fine.

Yep, that is the perfect scenario for the RAII (resource acquisition is
initialization) idiom. The new C++0x standard library provides for this
80% bread-and-butter business the so-called lock_guard class which has
exactly the simple constructor/destructor API as your type.

> sometime I must acquire a lock for few instructions, then release it
> in the middle of a big function. I use braces to get timely
> destructors, but I find the "middle of nowhere" braces kind of
> embarrassing.

Yes, in some situations we have these kinds of code flow disruptions
that are hard to get rid of. For such situations the C++0x library
provides the lock type unique_lock which is able to release and to
re-acquire a new lock.

> I would like to have something like the using keyword in c#.
> Is there a way to fake it in C++ ?

Not extremely much more. You may consider the Scope Guard as a more
general form:

http://www.drdobbs.com/184403758

The Loki library

http://loki-lib.sourceforge.net/index.php?n=Main.HomePage

contains also this component.

> for now I'm using an if to do it.
>
>
> void someFunc()
> {
> // do some stuff
> ...
> // now time to update share data
> if (Lock myLock = Lock(data_mutex))
> {
> //use locked data
> ....
> } // Unlock done by destructor
>
> // do more stuff
> ...
> }
>
> Is it good programming ?

Looks OK to me.

HTH & Greetings from Bremen,

Daniel Krügler

Dragan Milenkovic

unread,
Nov 26, 2010, 9:38:07 AM11/26/10
to

On 11/25/2010 11:48 PM, Daniel Anderson wrote:
>
> Hi!
>
> I often have to acquire locks and release them after I'm finished with
> them.
> I use constructor/destructor to acquire& release locks. everything

> works fine.
> sometime I must acquire a lock for few instructions, then release it
> in the middle of a big function. I use braces to get timely
> destructors, but I find the "middle of nowhere" braces kind of
> embarrassing.

Braces are good. You introduce a lock with the specified lifetime.
How does "if" make it any different?

--
Dragan

Gene Bushuyev

unread,
Nov 26, 2010, 7:19:53 PM11/26/10
to

On Nov 25, 5:48 pm, Daniel Anderson <woni...@gmail.com> wrote:
> Hi!
>
> I often have to acquire locks and release them after I'm finished with
> them.
> I use constructor/destructor to acquire & release locks. everything
> works fine.
> sometime I must acquire a lock for few instructions, then release it
> in the middle of a big function. I use braces to get timely
> destructors, but I find the "middle of nowhere" braces kind of
> embarrassing.

I guess it's a matter of taste. For me the curly braces are very
natural way of denoting the block.

> something like:
>
> struct Lock
> {
> Lock(Mutex& mtx) mtx_(mtx) { mtx.lock(); }
> ~Lock() { mtx_.unlock(); }
> operator bool() { return true;}
>
> };

Putting aside the errors in the code above, the only reason "operator
bool" exists in the class is to make if() construct possible, it's not
required for Lock proper functionality, which violates a good design
rule: make interface complete and minimal.

>
> void someFunc()
> {
> // do some stuff
> ...
> // now time to update share data
> {
> Lock myLock(data_mutex);
> //use locked data
> ....
> } // destructor called
> // do more stuff
> ...
>
> }
>
> I would like to have something like the using keyword in c#.
> Is there a way to fake it in C++ ?

That's one of the common mistakes people switching to another language
do -- is trying to fake what they are used to in a different language.
That usually causes grief for everybody who has to deal with that
code. Each language commands its own style, the only way to write good
code is to learn and use it.

> for now I'm using an if to do it.
>
> void someFunc()
> {
> // do some stuff
> ...
> // now time to update share data
> if (Lock myLock = Lock(data_mutex))
> {

That assumes that Lock is copy-constructible or move-constructible,
which it's not -- because mutex is neither copy-constructible nor move-
constructible. Allowing that would lead to unsafe code causing
deadlocks or races.

Michael Doubez

unread,
Nov 26, 2010, 7:22:02 PM11/26/10
to

On 25 nov, 23:48, Daniel Anderson <woni...@gmail.com> wrote:
> Hi!
>
> I often have to acquire locks and release them after I'm finished with
> them.
> I use constructor/destructor to acquire & release locks. everything
> works fine.
> sometime I must acquire a lock for few instructions, then release it
> in the middle of a big function. I use braces to get timely
> destructors, but I find the "middle of nowhere" braces kind of
> embarrassing.

Really ?
Sometimes I use them to separated unrelated sections of a function
body:

void foo()
{
{ // do foo
...
}

{ // do bar
...
}
}

> something like:
>
> struct Lock
> {
> Lock(Mutex& mtx) mtx_(mtx) { mtx.lock(); }
> ~Lock() { mtx_.unlock(); }
> operator bool() { return true;}
>
> };
>
> void someFunc()
> {
> // do some stuff
> ...
> // now time to update share data
> {
> Lock myLock(data_mutex);
> //use locked data
> ....
> } // destructor called
> // do more stuff
> ...
>
> }
>
> I would like to have something like the using keyword in c#.
> Is there a way to fake it in C++ ?

If you really want to do it. You could always use a macro but IMO it
would be dangerous.

> for now I'm using an if to do it.
>
> void someFunc()
> {
> // do some stuff
> ...
> // now time to update share data
> if (Lock myLock = Lock(data_mutex))
> {
> //use locked data
> ....
> } // Unlock done by destructor
>
> // do more stuff
> ...
>
> }
>
> Is it good programming ?
> Is there a better way ?

Why not simply align the opening parenthesis with the lock:
{ Lock myLock(mutex)
...
}

--
Michael

Pete Becker

unread,
Nov 26, 2010, 7:20:59 PM11/26/10
to

On 2010-11-25 11:48:37 -0500, Daniel Anderson said:

> Hi!
> I often have to acquire locks and release them after I'm finished with
> them.
> I use constructor/destructor to acquire & release locks. everything
> works fine.
> sometime I must acquire a lock for few instructions, then release it
> in the middle of a big function. I use braces to get timely
> destructors, but I find the "middle of nowhere" braces kind of
> embarrassing.
> something like:
> struct Lock
> {
> Lock(Mutex& mtx) mtx_(mtx) { mtx.lock(); }
> ~Lock() { mtx_.unlock(); }
> operator bool() { return true;}
> };
> void someFunc()
> {
> // do some stuff
> ...
> // now time to update share data
> {
> Lock myLock(data_mutex);
> //use locked data
> ....
> } // destructor called

You don't loke "middle of nowhere" braces, so you add a meaningless if statement and an otherwise pointless operator bool? Stick with the braces. <g>

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The Standard C++ Library Extensions: a Tutorial and Reference (www.petebecker.com/tr1book)

hak...@gmail.com

unread,
Nov 26, 2010, 7:22:25 PM11/26/10
to

On Nov 25, 5:48 pm, Daniel Anderson <woni...@gmail.com> wrote:
> Hi!
>
> I often have to acquire locks and release them after I'm finished with
> them.
> I use constructor/destructor to acquire & release locks. everything
> works fine.
> sometime I must acquire a lock for few instructions, then release it
> in the middle of a big function. I use braces to get timely
> destructors, but I find the "middle of nowhere" braces kind of
> embarrassing.
> something like:
>
> struct Lock
> {
> Lock(Mutex& mtx) mtx_(mtx) { mtx.lock(); }
> ~Lock() { mtx_.unlock(); }
> operator bool() { return true;}
>
> };

Since your Lock type depends on Mutex, why not just use the straight
Mutex and lock and unlock as you please?

> void someFunc()
> {
> // do some stuff
> ...
> // now time to update share data
> {
> Lock myLock(data_mutex);
> //use locked data
> ....
> } // destructor called
> // do more stuff
> ...
>
> }

Some don't even know or haven long forgotten that you can create
blocks arbitrarily like this. I agree that it doesn't look nice, but
it has a lot of uses and i think there's nothing wrong with using it.
It's an incredibly simple and elegant way of solving this problem.

> I would like to have something like the using keyword in c#.
> Is there a way to fake it in C++ ?

This is a C++ forum. C# is relevant to this question, but for those of
us who haven't worked with it, please post a short example.

> for now I'm using an if to do it.
>
> void someFunc()
> {
> // do some stuff
> ...
> // now time to update share data
> if (Lock myLock = Lock(data_mutex))
> {
> //use locked data
> ....
> } // Unlock done by destructor
>
> // do more stuff
> ...
>
> }

You seem to be implying that this if statement will always evaluate to
true (since i assume this code is equivalent to your first example),
but when i see an "if" in any code, i always assume that it will
sometimes not evaluate to true. On the other hand, it reminds me of
this:
std::weak_ptr<int> wp;
void f() {
if( std::shared_ptr<int> sp = wp.lock() )
; // do something
}

> Is it good programming ?

What a subjective question!

> Is there a better way ?

I think creating an arbitrary scope is one of the simplest and least
error prone ways to do this. I'm sure at least one person (if not you)
will disagree with me, but i like simple. I suppose you could create a
class that inputs a function, locks, calls the function, then unlocks,
and you could use C++0x lambdas to integrate it into your current code
without too much refactoring, but that means you'll have to maintain
the locking class and every function/class/etc that uses it. I guess
i'm not the most articulate so i'll use someone else's words:
"Perfection is achieved not when you have nothing more to add, but
when you have nothing left to take away." ~ Antoine de Saint-Exupery.

news

unread,
Nov 26, 2010, 7:21:07 PM11/26/10
to

In comp.lang.c++ Daniel Anderson <won...@gmail.com> wrote:
> but I find the "middle of nowhere" braces kind of
> embarrassing.

I don't think there's anything wrong with them, especially if you
precede the block with a comment clarifying the reason. It's a pretty
common pattern to restrict the lifetime of objects. (One concrete example
where it's commonly used is the "release the memory taken by a std::vector
via swapping" paradigm.)

gwowen

unread,
Nov 26, 2010, 7:21:20 PM11/26/10
to

On Nov 25, 10:48 pm, Daniel Anderson <woni...@gmail.com> wrote:
> Hi!
>
> I often have to acquire locks and release them after I'm finished with
> them.
> I use constructor/destructor to acquire & release locks. everything
> works fine.

Good. What's the problem here?

> I use braces to get timely destructors, but I find the "middle of nowhere" braces kind of embarrassing.

Why? The braces denote the lifetime of the objects declared after the
opening brace. It's *exactly* the concept you want.

> I would like to have something like the using keyword in c#.
> Is there a way to fake it in C++ ?

Yes. Braces. Or a macro so those braces don't offend your
sensibilities. Try:
#define \
CREATEOBJECTWITHLIMITEDSCOPEWITHOUTUSINGBRACESBECAUSEIFINDTHEMEMBARRASINGWHATEVERTHEHELLTHATMEANS(x)
{x;
#define
DESTROYTHELASTSETOFOBJECTSWITHLIMITEDSCOPETHATICREATEDWITHOUTACLOSINGBRACE(x) }

Better?

Martin B.

unread,
Nov 26, 2010, 7:21:40 PM11/26/10
to

On 25.11.2010 23:48, Daniel Anderson wrote:
>
> Hi!
>
> I often have to acquire locks and release them after I'm finished with
> them.
> I use constructor/destructor to acquire& release locks. everything

> works fine.
> sometime I must acquire a lock for few instructions, then release it
> in the middle of a big function. I use braces to get timely
> destructors, but I find the "middle of nowhere" braces kind of
> embarrassing.
> something like:
>
> struct Lock
> {
> Lock(Mutex& mtx) mtx_(mtx) { mtx.lock(); }
> ~Lock() { mtx_.unlock(); }
> operator bool() { return true;}
> };
>

This is incomplete! You should never be able to copy a lock object.

> void someFunc()
> {
> // do some stuff
> ...
> // now time to update share data
> {
> Lock myLock(data_mutex);
> //use locked data
> ....
> } // destructor called
> // do more stuff
> ...
> }
>

So do I. I do not know of another way. Sometime I have considered this:
//...
{ Lock myLock(data_mutex);
// use locked data ...
}

But I don't find it much better. It save a line but potentially confuses pothers.

> I would like to have something like the using keyword in c#.
> Is there a way to fake it in C++ ?

I do not know of a way - but maybe you can find some code examples for the new C++0x threading features that provide a "better" way.

> for now I'm using an if to do it.
>
>
> void someFunc()
> {
> // do some stuff
> ...
> // now time to update share data
> if (Lock myLock = Lock(data_mutex))

And this will break down if you have a proper lock class that is non-copyable.
It is also confusing, because a lock will always evaluate to true (which is the whole point, I know), so there is no need for an if.

cheers,
Martin

Mickey

unread,
Nov 26, 2010, 7:20:51 PM11/26/10
to

I find the braces in the middle of nowhere quite a handy thing at
times.
I suppose you can expect Lock to fail so it would be wiser to follow
the if() {} style here. If the design says it will never fail then I
would go with the lonely braces-- unless you are expecting that you
might that check sometime in the future.

-- Jyoti

Goran

unread,
Nov 26, 2010, 7:22:08 PM11/26/10
to

Frankly, I find the "if" worse than a "standalone" block. It obscures
intention of the code (there an "if, but there is no "condition" to
enter the "if" block).

I don't know of a better way than what you've shown, and I don't
consider hanging blocks bad. If you are so bothered, there is nothing
wrong in creating a function specifically for your block. Imagine:

void SynchronizedPart(type1& p1, type2& p2, type3& p3)
{
lock l(mutex);
abuse(p1, p2, p3);
}

void someFunc()
{
// do stuff...

SynchronizedPart(d1, d2, d3);

// do more stuff
}

This arguably even reads better and you can be pretty sure that you'll
normally get no runtime overhead whatsoever (optimization will see
that there's only one use of SynchronizedPart and will inline it).

Also, with C++0x, perhaps some clever use of lambdas can even automate
creation of "synchronized" stuff, and I would be surprised if someone
didn't already do it e.g. with boost::lambda.

Goran.

Matt Calabrese

unread,
Nov 27, 2010, 12:40:01 AM11/27/10
to
On Nov 25, 5:48 pm, Daniel Anderson <woni...@gmail.com> wrote:
> I would like to have something like the using keyword in c#.
> Is there a way to fake it in C++ ?
> for now I'm using an if to do it.

The whole point of C# "using" is to specify a scope for an object and
its disposal. It's a way to emulate the behavior that C++ already
supports naturally -- by simply writing object declarations in C++ you
get the behavior of C# using. I'm not sure why you are treating it as
though it's a special feature of C#.

> Is it good programming ?
> Is there a better way ?

Your "if" example is not "bad" programming, just sort of silly and
unnecessary (and likely more confusing to someone reading your code).
The "better" way IMO is to just use braces as in your original
example. What do you think is so bad about plain braces?

Martin B.

unread,
Nov 27, 2010, 2:13:58 PM11/27/10
to
On 27.11.2010 01:22, Goran wrote:
>
> On Nov 25, 11:48 pm, Daniel Anderson<woni...@gmail.com> wrote:
>> [...]

> I don't know of a better way than what you've shown, and I don't
> consider hanging blocks bad. If you are so bothered, there is nothing
> wrong in creating a function specifically for your block. Imagine:
>
> void SynchronizedPart(type1& p1, type2& p2, type3& p3)
> {
> lock l(mutex);
> abuse(p1, p2, p3);
> }
>
> void someFunc()
> {
> // do stuff...
>
> SynchronizedPart(d1, d2, d3);
>
> // do more stuff
> }
>
> This arguably even reads better and you can be pretty sure that you'll
> normally get no runtime overhead whatsoever (optimization will see
> that there's only one use of SynchronizedPart and will inline it).
>

PLEASE, can we stop this whole ""no runtime overhead whatsoever (optimization
will see"" stuff? The optimizer is far more limited (some might call it stupid)
than such blanket statements admit.

For example, in the above snippet, unless SynchronizedPart is marked as static
or enclosed in an anonymous namespace, the compiler/optimizer should assume
external linkage and as such will treat this function no differently than any
other function, no matter how often it's used.

Oh wait, you could also mark it as inline, except, to quote one arguably popular
compilers[1] docs:

The inline keyword tells the compiler
that inline expansion is preferred.
However, the compiler can create a separate
instance of the function (instantiate) and
create standard calling linkages instead
of inserting the code inline.

And [2],
In some cases, the compiler will not inline
a particular function for mechanical reasons.
For example, the compiler will not inline:

* A function if it would result in mixing
both SEH and C++ EH.
* Some functions with copy constructed
objects passed by value[...]
* Functions returning an unwindable
object by value[...]
* [...]
* A function with a try (C++ exception handling) statement.

So if your fn is containing a simple innocent try block, MS VC++ ain't ever able
to inline it! If SynchronizedPart happens to return a non-void non-trivial
object by value: no inlining!

NOTE - this reply is not intended to imply that a user should overmuch care
about these inlining *details*, nor should it imply that the use of a separate
function should be avoided!

Its point is rather to point out that peppering our replys with "trust your
optimizer" statements is by no means always appropriate.

cheers,
Martin


[1] MS VC++ 2010 inline keywords :
http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx

[2] Compiler Warning (level 4) C4714 :
http://msdn.microsoft.com/en-us/library/a98sb923%28v=VS.100%29.aspx

Daniel Anderson

unread,
Nov 28, 2010, 9:29:54 AM11/28/10
to

On Nov 26, 8:19 pm, Gene Bushuyev <408...@gmail.com> wrote:
> On Nov 25, 5:48 pm, Daniel Anderson <woni...@gmail.com> wrote:
>
>> Hi!
>
>> I often have to acquire locks and release them after I'm finished with
>> them.
>> I use constructor/destructor to acquire & release locks. everything
>> works fine.
>> sometime I must acquire a lock for few instructions, then release it
>> in the middle of a big function. I use braces to get timely
>> destructors, but I find the "middle of nowhere" braces kind of
>> embarrassing.
>
> I guess it's a matter of taste. For me the curly braces are very
> natural way of denoting the block.
>
>> something like:
>
>> struct Lock
>> {
>> Lock(Mutex& mtx) mtx_(mtx) { mtx.lock(); }
>> ~Lock() { mtx_.unlock(); }
>> operator bool() { return true;}
>
>> };
>
> Putting aside the errors in the code above, the only reason "operator
> bool" exists in the class is to make if() construct possible, it's not
> required for Lock proper functionality, which violates a good design
> rule: make interface complete and minimal.
>
>
well, yes in the example I've shown bool always return true, but it
could be use in case lock could not be acquired
which would allow an else part.
on this I have not decided if I should throw in the constructor or use
the else part. I will probably play with it a bit before deciding

>
>> void someFunc()
>> {
>> // do some stuff
>> ...
>> // now time to update share data
>> {
>> Lock myLock(data_mutex);
>> //use locked data
>> ....
>> } // destructor called
>> // do more stuff
>> ...
>
>> }
>
>> I would like to have something like the using keyword in c#.
>> Is there a way to fake it in C++ ?
>
> That's one of the common mistakes people switching to another language
> do -- is trying to fake what they are used to in a different language.
> That usually causes grief for everybody who has to deal with that
> code. Each language commands its own style, the only way to write good
> code is to learn and use it.
>

I am not switching from c#, I was using an example. I find in this
case the C# syntax clearer.
Language do not command style, it is people who define style, language
is only a tool

>> for now I'm using an if to do it.
>
>> void someFunc()
>> {
>> // do some stuff
>> ...
>> // now time to update share data
>> if (Lock myLock = Lock(data_mutex))
>> {
>
> That assumes that Lock is copy-constructible or move-constructible,
> which it's not -- because mutex is neither copy-constructible nor move-
> constructible. Allowing that would lead to unsafe code causing
> deadlocks or races.

yes, but it happen that my compiler is getting rid of the copy
contructor and directly construct my object as if I was doing:

if (Lock myLock(data_mutex))

I know it is not portable, but this is not the point of this post.

Daniel Anderson

unread,
Nov 28, 2010, 9:39:01 AM11/28/10
to

On Nov 26, 8:22 pm, "Hak...@gmail.com" <hak...@gmail.com> wrote:
> On Nov 25, 5:48 pm, Daniel Anderson <woni...@gmail.com> wrote:
>
>
>
>
>
>
>
>
>
>> Hi!
>
>> I often have to acquire locks and release them after I'm finished with
>> them.
>> I use constructor/destructor to acquire & release locks. everything
>> works fine.
>> sometime I must acquire a lock for few instructions, then release it
>> in the middle of a big function. I use braces to get timely
>> destructors, but I find the "middle of nowhere" braces kind of
>> embarrassing.
>> something like:
>
>> struct Lock
>> {
>> Lock(Mutex& mtx) mtx_(mtx) { mtx.lock(); }
>> ~Lock() { mtx_.unlock(); }
>> operator bool() { return true;}
>
>> };
>
> Since your Lock type depends on Mutex, why not just use the straight
> Mutex and lock and unlock as you please?

Because of exception!

>
>> void someFunc()
>> {
>> // do some stuff
>> ...
>> // now time to update share data
>> {
>> Lock myLock(data_mutex);
>> //use locked data
>> ....
>> } // destructor called
>> // do more stuff
>> ...
>
>> }
>
> Some don't even know or haven long forgotten that you can create
> blocks arbitrarily like this. I agree that it doesn't look nice, but
> it has a lot of uses and i think there's nothing wrong with using it.
> It's an incredibly simple and elegant way of solving this problem.

Simple, yes. I've doing it for a long time
elegant, I use to think so, until someone remove some braces in my
code that where there for RAII, since I do not think it is elegant

according to Plato (or was it Socrates) good is not subjective :)

>
>> Is there a better way ?
>
> I think creating an arbitrary scope is one of the simplest and least
> error prone ways to do this. I'm sure at least one person (if not you)
> will disagree with me, but i like simple. I suppose you could create a

I do not disagree, I'm just looking for advice

> class that inputs a function, locks, calls the function, then unlocks,
> and you could use C++0x lambdas to integrate it into your current code
> without too much refactoring, but that means you'll have to maintain
> the locking class and every function/class/etc that uses it. I guess
> i'm not the most articulate so i'll use someone else's words:
> "Perfection is achieved not when you have nothing more to add, but
> when you have nothing left to take away." ~ Antoine de Saint-Exupery.

this is a good guy this Antoine.

Daniel Anderson

unread,
Nov 28, 2010, 9:31:21 AM11/28/10
to

On Nov 27, 1:40 am, Matt Calabrese <rivo...@gmail.com> wrote:
> On Nov 25, 5:48 pm, Daniel Anderson <woni...@gmail.com> wrote:
>
>> I would like to have something like the using keyword in c#.
>> Is there a way to fake it in C++ ?
>> for now I'm using an if to do it.
>
> The whole point of C# "using" is to specify a scope for an object and
> its disposal. It's a way to emulate the behavior that C++ already
> supports naturally -- by simply writing object declarations in C++ you
> get the behavior of C# using. I'm not sure why you are treating it as
> though it's a special feature of C#.
>
>> Is it good programming ?
>> Is there a better way ?
>
> Your "if" example is not "bad" programming, just sort of silly and
> unnecessary (and likely more confusing to someone reading your code).
> The "better" way IMO is to just use braces as in your original
> example. What do you think is so bad about plain braces?

I've worked with plenty of people at different places.
where I work now, we have plenty of "not talented" programmer (maybe
I'm one of them) . In the past it happen that some of my stand alone
braces where removed by some programmers that did not understand the
idioms.
Now I cannot put comments to say why I've put braces, as my boss
forbid them.
For him putting comments means that the code is not clear and he does
not want code that is not clear.
Also he reasoned that if there is no comments, people will have to
understand the code before modifying it.

So I'm trying to find a way that people will not remove my braces.

doing:

If (Lock Mylock(mutex)) {...}

could be read by others as: If I could lock this mutex, do this

while empty braces do not seem to convey more meaning than: hey I
starting a new block

I could have use a for loop, as it seems more natural to declare
variable
ex:

For(Lock myLock(mutex); myLock.IsLock(); MyLock.Unlock())
{
// do your deed
}

But the reading of the code does not convey the proper meaning (I
think)

Anyway, I understand people comments. I just came here for some
advices, and to see if someone thought about another way of doing the
locking/unlocking

Goran

unread,
Nov 29, 2010, 4:57:35 AM11/29/10
to

On Nov 27, 8:13 pm, "Martin B." <0xCDCDC...@gmx.at> wrote:
> On 27.11.2010 01:22, Goran wrote:
> > On Nov 25, 11:48 pm, Daniel Anderson<woni...@gmail.com> wrote:
> >> [...]
> > I don't know of a better way than what you've shown, and I don't
> > consider hanging blocks bad. If you are so bothered, there is nothing
> > wrong in creating a function specifically for your block. Imagine:
>
> > void SynchronizedPart(type1& p1, type2& p2, type3& p3)
> > {
> > lock l(mutex);
> > abuse(p1, p2, p3);
> > }
>
> > void someFunc()
> > {
> > // do stuff...
>
> > SynchronizedPart(d1, d2, d3);
>
> > // do more stuff
> > }
>
> > This arguably even reads better and you can be pretty sure that you'll
> > normally get no runtime overhead whatsoever (optimization will see
> > that there's only one use of SynchronizedPart and will inline it).
>
> PLEASE, can we stop this whole ""no runtime overhead whatsoever (optimization
> will see"" stuff? The optimizer is far more limited (some might call it stupid)
> than such blanket statements admit.
>
> For example, in the above snippet, unless SynchronizedPart is marked as static
> or enclosed in an anonymous namespace, the compiler/optimizer should assume
> external linkage and as such will treat this function no differently than any
> other function, no matter how often it's used.

Well, I did write "you can be pretty sure that you'll normally get no
runtime overhead whatsoever" ( reading again, that "normally" is
rather bad writing :-) ).

I actually disagree with external linkage part. Compilers both can and
will inline the function even when it has external linkage. I was
surprised when I first saw that, but now I know they do it, and it's a
good thing :-) .

Also, here, we're dealing with synchronization primitives, which I
think are more expensive than a function call (provided that there
__is__ one). If nothing else, there's a function call to enter the
primitive.

> ... point is rather to point out that peppering our replys with "trust your


> optimizer" statements is by no means always appropriate.

I firmly believe that in this case, it is appropriate to trust it.
This is of course not to say that I __know__ that there will not be
any overhead, one can't ever tell without actual code.

Goran.

Maxim Yegorushkin

unread,
Nov 29, 2010, 5:04:15 AM11/29/10
to
On 25/11/10 22:48, Daniel Anderson wrote:

> I often have to acquire locks and release them after I'm finished with
> them.

> I use constructor/destructor to acquire& release locks. everything


> works fine.
> sometime I must acquire a lock for few instructions, then release it
> in the middle of a big function. I use braces to get timely
> destructors, but I find the "middle of nowhere" braces kind of
> embarrassing.
> something like:
>
> struct Lock
> {
> Lock(Mutex& mtx) mtx_(mtx) { mtx.lock(); }
> ~Lock() { mtx_.unlock(); }
> operator bool() { return true;}
> };
>
> void someFunc()
> {
> // do some stuff
> ...
> // now time to update share data
> {
> Lock myLock(data_mutex);
> //use locked data
> ....
> } // destructor called
> // do more stuff
> ...
> }
>
> I would like to have something like the using keyword in c#.
> Is there a way to fake it in C++ ?

The alternative to creating a scope just to unlock the mutex at a
particlular point, it may be simpler to provide unlock() function on the
lock, e.g.:

struct Lock
{
Mutex* mtx_;
Lock(Mutex& mtx) : mtx_(&mtx) { mtx_->lock(); }
~Lock() { this->unlock(); }
void unlock() {
if(mtx_) {
mtx_->unlock();
mtx_ = 0;
}
}
};

void someFunc()
{
Lock myLock(data_mutex);
// ... use locked data ...
myLock.unlock(); // unlock long before leaving the scope
// ... more code ...
}

Notice in the above how no artificial scope is introduced and
myLock.unlock() does exactly what it says.

> for now I'm using an if to do it.
>
>
> void someFunc()
> {
> // do some stuff
> ...
> // now time to update share data
> if (Lock myLock = Lock(data_mutex))
> {
> //use locked data
> ....
> } // Unlock done by destructor
>
> // do more stuff
> ...
> }
>
> Is it good programming ?

If statement naturally means it is conditional, so that a reader of such
code may be led to think that obtaining the lock may fail and the
control flow may skip the block guarded by if.

--
Max

Matt Calabrese

unread,
Nov 29, 2010, 5:02:50 AM11/29/10
to
On Nov 28, 9:31 am, Daniel Anderson <woni...@gmail.com> wrote:
> I've worked with plenty of people at different places.
> where I work now, we have plenty of "not talented" programmer (maybe
> I'm one of them) . In the past it happen that some of my stand alone
> braces where removed by some programmers that did not understand the
> idioms.
> Now I cannot put comments to say why I've put braces, as my boss
> forbid them.
> For him putting comments means that the code is not clear and he does
> not want code that is not clear.
> Also he reasoned that if there is no comments, people will have to
> understand the code before modifying it.
>
> So I'm trying to find a way that people will not remove my braces.

I think you are trying to solve the wrong "problem" here. The issue
isn't clarity, it's a lack of competence of other programmers in the
language you are using. It would be one thing if you were doing
something relatively complicated such as template metaprogramming that
others may have trouble with, but you are simply using RAII for
scoping a lock, which is not exactly an uncommon odd idiom at all
whether it be for locks or for more general resource management. If
people are just randomly removing braces for no reason then they need
to be informed to simply not do that and understand why. Rather than
complicate code by introducing unnecessary control statements couldn't
someone just send out a brief email explaining that braces are not
superfluous because they are there for RAII? I realize that not
everyone has the same amount of experience with C++ and I understand
that it may seem subtle to people new to the language, but I can't
imagine that this would be something horribly difficult to teach. If
people understand what a destructor is then the point should be easy
to make clear.

Anyway, that's just my opinion on the matter. Obviously it's up to
your boss, but I would at least suggest this.

Martin B.

unread,
Nov 29, 2010, 2:19:39 PM11/29/10
to
On 28.11.2010 15:31, Daniel Anderson wrote:
>
> On Nov 27, 1:40 am, Matt Calabrese<rivo...@gmail.com> wrote:
>> On Nov 25, 5:48 pm, Daniel Anderson<woni...@gmail.com> wrote:
>>
>>> I would like to have something like the using keyword in c#.
>>> Is there a way to fake it in C++ ?
>>> for now I'm using an if to do it.
>>
>> The whole point of C# "using" is to specify a scope for an object and
>> its disposal. It's a way to emulate the behavior that C++ already
>> [...]

>> The "better" way IMO is to just use braces as in your original
>> example. What do you think is so bad about plain braces?
>
> I've worked with plenty of people at different places.
> where I work now, we have plenty of "not talented" programmer (maybe
> I'm one of them) . In the past it happen that some of my stand alone
> braces where removed by some programmers that did not understand the
> idioms.
> Now I cannot put comments to say why I've put braces, as my boss
> forbid them.
> For him putting comments means that the code is not clear and he does
> not want code that is not clear.
> Also he reasoned that if there is no comments, people will have to
> understand the code before modifying it.
>
> So I'm trying to find a way that people will not remove my braces.
>

Oh my :-)

In this case, I would reccomend a macro. Seriously. It may actually be
the least trouble.

#define START_LOCKSCOPE(mtx) \
{ Lock localLock(mtx); \
/**/

void someFunc()
{
// do some stuff
...
// now time to update share data

START_LOCKSCOPE(data_mutex)


Lock myLock(data_mutex);
//use locked data
....
}

// do more stuff
...
}

Of course, better would be to:
* Educate your colleagues about this idom. (It's not *that* hard)
* Convince your boss that some comments might be ok.


cheers,
Martin

Paavo Helde

unread,
Nov 29, 2010, 2:17:15 PM11/29/10
to
Daniel Anderson <won...@gmail.com> wrote in news:6e1a660e-fcd7-48c8-
8fcf-f3f...@r21g2000pri.googlegroups.com:

>
> I've worked with plenty of people at different places.
> where I work now, we have plenty of "not talented" programmer (maybe
> I'm one of them) . In the past it happen that some of my stand alone
> braces where removed by some programmers that did not understand the
> idioms.
> Now I cannot put comments to say why I've put braces, as my boss
> forbid them.
> For him putting comments means that the code is not clear and he does
> not want code that is not clear.
> Also he reasoned that if there is no comments, people will have to
> understand the code before modifying it.
>
> So I'm trying to find a way that people will not remove my braces.

In this case I would suggest
#define BEGIN_LOCKED_SECTION(mutex) {Lock myLock(mutex);
#define END_LOCKED_SECTION }

but I'm sure your boss has forbidden macros as well ;-)

Francis Glassborow

unread,
Nov 29, 2010, 2:16:38 PM11/29/10
to
On 28/11/2010 14:39, Daniel Anderson wrote:
>
> On Nov 26, 8:22 pm, "Hak...@gmail.com"<hak...@gmail.com> wrote:
>> On Nov 25, 5:48 pm, Daniel Anderson<woni...@gmail.com> wrote:

>
>>
>>> void someFunc()
>>> {
>>> // do some stuff
>>> ...
>>> // now time to update share data
>>> {
>>> Lock myLock(data_mutex);
>>> //use locked data
>>> ....
>>> } // destructor called
>>> // do more stuff
>>> ...
>>
>>> }
>>
>> Some don't even know or haven long forgotten that you can create
>> blocks arbitrarily like this. I agree that it doesn't look nice, but
>> it has a lot of uses and i think there's nothing wrong with using it.
>> It's an incredibly simple and elegant way of solving this problem.
> Simple, yes. I've doing it for a long time
> elegant, I use to think so, until someone remove some braces in my
> code that where there for RAII, since I do not think it is elegant

Well elegance is often a matter ot taste, but anyone who remove braces
from a piece of code without understanding the code gets much of what
they deserve. OTOH anyone who uses this kind of idiom without a comment
is being rather optimistic about the capabilities of maintenance
programmers.

>>
>>> I would like to have something like the using keyword in c#.
>>> Is there a way to fake it in C++ ?
>>
>> This is a C++ forum. C# is relevant to this question, but for those of
>> us who haven't worked with it, please post a short example.

>>
>>> for now I'm using an if to do it.
>>
>>> void someFunc()
>>> {
>>> // do some stuff
>>> ...
>>> // now time to update share data
>>> if (Lock myLock = Lock(data_mutex))
>>> {
>>> //use locked data
>>> ....
>>> } // Unlock done by destructor

Well if you really want something other than comments to stop idiots
breaking your code then

bool just_once(false);
do {
// place your code here
} while(just_once);

Though i think that is awful :)

>>
>>> // do more stuff
>>> ...
>>
>>> }

>>


>>> Is it good programming ?
>>
>> What a subjective question!
>
> according to Plato (or was it Socrates) good is not subjective :)

The word 'good' has several meanings and in the current context I yake
it to mean 'socially acceptable' (the society being programmers) as
opposed to morally good which I think was what the Greek philosophers
were meaning. And I guess that in classical Greek the words for the two
meanings were almost certainly different but it is more than 50 years
since I had to toil at classical Greek.


--
Note that robinton.demon.co.uk addresses are no longer valid.

hak...@gmail.com

unread,
Nov 29, 2010, 2:18:32 PM11/29/10
to
On Nov 28, 9:31 am, Daniel Anderson <woni...@gmail.com> wrote:

> I've worked with plenty of people at different places.
> where I work now, we have plenty of "not talented" programmer (maybe
> I'm one of them) . In the past it happen that some of my stand alone
> braces where removed by some programmers that did not understand the
> idioms.
> Now I cannot put comments to say why I've put braces, as my boss
> forbid them.
> For him putting comments means that the code is not clear and he does
> not want code that is not clear.
> Also he reasoned that if there is no comments, people will have to
> understand the code before modifying it.

That sounds... less than ideal. Well, if it's really so bad, let me
expand on the solution i mentioned, but give an example this time.

template< typename Func >
void lock_do( Mutex& mtx, Func f )
{
Lock l( mtx );
f();
}

So now

> void someFunc()
> {
> // do some stuff
> ...
> // now time to update share data
> {
> Lock myLock(data_mutex);
> //use locked data
> ....
> } // destructor called
> // do more stuff
> ...
>
> }

becomes

void someFunc()
{
// do some stuff
...
// now time to update share data

lock_do( data_mutex, [](/*...*/) -> void {
//use locked data
....
} );


// do more stuff
...
}

I haven't tested the code because i have never used lambdas before in
actual code, but the idea's what's important. If you can't comment
your code, and you can't teach those around you about arbitrary
braces, but you can use c++0x features, this is a compromise. Without c
++0x, i guess you could still move all that code to external functions
if you wanted.

Of coarse, you always have the chance that someone comes by and
doesn't understand the code, but when they see that scary lambda
syntax, maybe they'll flee before modifying it. ;)

> >> Is it good programming ?
>

> > What a subjective question!
>
> according to Plato (or was it Socrates) good is not subjective :)

A little off topic, but:
We all know that charity is good and murder is bad, but think of how
many thousands of years of social evolution it took us humans to come
to that conclusion. In contrast, none of what we now call programming
existed even 100 years ago. We can't even all agree on what editor to
use, brace style, naming conventions, or language. One might say a
macro is objectively bad, but others might say when used right, macros
are objectively good.

Perhaps if good was not subjective, we wouldn't have to share our
ideas like this in order to be better at programming.

Martin B.

unread,
Nov 29, 2010, 2:29:55 PM11/29/10
to
On 29.11.2010 10:57, Goran wrote:
>
> On Nov 27, 8:13 pm, "Martin B."<0xCDCDC...@gmx.at> wrote:
>> On 27.11.2010 01:22, Goran wrote:
>>> On Nov 25, 11:48 pm, Daniel Anderson<woni...@gmail.com> wrote:
>>>> [...]
>>> I don't know of a better way than what you've shown, and I don't
>>> consider hanging blocks bad. If you are so bothered, there is nothing
>>> wrong in creating a function specifically for your block. Imagine:
>>
>>> [...]

>>> normally get no runtime overhead whatsoever (optimization will see
>>> that there's only one use of SynchronizedPart and will inline it).
>>
>> PLEASE, can we stop this whole ""no runtime overhead whatsoever (optimization
>> will see"" stuff? [...]

>>
>> For example, in the above snippet, unless SynchronizedPart is marked as static
>> or enclosed in an anonymous namespace, the compiler/optimizer should assume
>> external linkage and as such will treat this function no differently than any
>> other function, no matter how often it's used.
> [...]

>
> I actually disagree with external linkage part. Compilers both can and
> will inline the function even when it has external linkage. I was
> surprised when I first saw that, but now I know they do it, and it's a
> good thing :-) .
>

Which compiler? Which options? Which platform? Which version?

I agree that a compiler+optimizer+linker *may* inline external-linkage
functions if something like whole program optimization is enabled, in
which case "it" knows that it does not need the external linkage.

Otherwise I do not see how it could make sense for a *compiler* to
inline a function *not marked* as inline if it has to expect the fn to
be used (by the linker) from another translation unit.

>
>> ... point is rather to point out that peppering our replys with "trust your
>> optimizer" statements is by no means always appropriate.
>
> I firmly believe that in this case, it is appropriate to trust it.
> This is of course not to say that I __know__ that there will not be
> any overhead, one can't ever tell without actual code.
>

If the OP snippet "//use locked data" is longer than a few lines, I
would trust the VC++ optimizer to *not* inline the separate function,
even if its only used once. (Which probably wouldn't hurt overmuch, as
the fn call overhead would likely be negligible.

cheers,
Martin

Goran

unread,
Nov 29, 2010, 2:28:46 PM11/29/10
to
On Nov 29, 11:04 am, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:

I don't think that's good, not in the general case. It drastically
changes lock duration in face of exceptions. Without, lock is there
from ctor of lock to unlock(). With, it's from ctor to the end of the
scope. However smart we think we are, we will mess it up ;-).

Also, you introduced performance penalty (an if and an an assignment
to 0).

Goran.


--

Michael Doubez

unread,
Nov 29, 2010, 2:27:42 PM11/29/10
to

You can always name your lock variables:
{ Lock
Don_t_delete_this_brace_It_defines_the_lifetime_of_the_lock_of(mutex);
...
}

I suggest you put that as a snippet :)

> Also he reasoned that if there is no comments, people will have to
> understand the code before modifying it.

Time to be creative:)

assert( sedition && "this is not a comment" );

> So I'm trying to find a way that people will not remove my braces.

Ok. So the solution may be to have a resetable lock:

struct Lock: non_copiable()
{
Lock(Mutex& mtx) mtx_(&mtx) { mtx.lock(); }
~Lock() { unlock(); }


void unlock() { if(mtx_) {mtx_->unlock();mtx_=0;} }

private:
Mutex* _mtx;
};

And use:
Lock lock(mutex)
...
lock.unlock();

You will have RAII unlock in case of early return and you have unlock
whenever you want.
The people after you will have to look for when the lock is released
but if it is what your boss does want.

--
Michael

Rick Wheeler

unread,
Nov 29, 2010, 2:25:20 PM11/29/10
to

The fact that someone removed your braces should be a testimonial to
your boss that comments are not in lieu of clarity, but are indeed
necessary to achieve it. Moreover, inventing a "using" substitute (and
even the if clause, for clause, or whatever) is an attempt to add
commentary through keyword expressions that somehow deserve to live.
In the end, they fall into the category of extraneous code which
contrarily obscures clarity. Unless you actually have an "else"
condition, the argument for the "if" becomes pure rationalization.
Most readers of C++ know exactly what you're doing when scoping code
blocks. And yes, most if not all of those authors would comment their
intentions if they were ever in doubt. Perhaps over time you can
respectfully enlighten your boss in these concepts.

I don't think your question about early unlocking was given much
discussion. But you can always add explicit lock/unlock members along
with sufficient state to avoid redundancy in those actions.

Rick

Miles Bader

unread,
Nov 29, 2010, 2:30:56 PM11/29/10
to
Matt Calabrese <riv...@gmail.com> writes:
> Rather than complicate code by introducing unnecessary control
> statements couldn't someone just send out a brief email explaining
> that braces are not superfluous because they are there for RAII? I
> realize that not everyone has the same amount of experience with C++
> and I understand that it may seem subtle to people new to the
> language, but I can't imagine that this would be something horribly
> difficult to teach. If people understand what a destructor is then the
> point should be easy to make clear.

Or if this particular behavior is too pervasive to fix with an email,
put a comment in the code:

// This block delimits the scope of the GUARD variable
// (don't remove the braces!)
{
LockGuard guard (some_mutex);
...
}

Yeah, it's kinda ugly, but it serves to teach those people that were
incorrectly modifying the code why they shouldn't, instead of
obfuscating with "fake" syntax.

-miles

--
Any man who is a triangle, has thee right, when in Cartesian Space,
to have angles, which when summed, come to know more, nor no less,
than nine score degrees, should he so wish. [TEMPLE OV THEE LEMUR]

James Kanze

unread,
Nov 29, 2010, 2:32:02 PM11/29/10
to
On Nov 28, 2:31 pm, Daniel Anderson <woni...@gmail.com> wrote:
> On Nov 27, 1:40 am, Matt Calabrese <rivo...@gmail.com> wrote:

[...]


> I've worked with plenty of people at different places.
> where I work now, we have plenty of "not talented" programmer (maybe
> I'm one of them) . In the past it happen that some of my stand alone
> braces where removed by some programmers that did not understand the
> idioms.
> Now I cannot put comments to say why I've put braces, as my boss
> forbid them.
> For him putting comments means that the code is not clear and he does
> not want code that is not clear.
> Also he reasoned that if there is no comments, people will have to
> understand the code before modifying it.

And the fact that people have removed your braces because they
didn't understand the code has proved that this last statement
doesn't hold.

My immediate reaction when reading your original posting was:
write shorter functions. Cases where you'd want to limit the
scope of a lock are rare. But realistically, they do occur.
And the only correct way of handling them is to add the extra
braces. Preferably with a comment. Ideally, all code should be
simple enough to be understood without comments, but
practically, code solving a complicated problem will require
some complexity somewhere.

> So I'm trying to find a way that people will not remove my braces.

There are two parts to the correct solution. The first is to
get rid of anyone who deletes code without understanding why it
was there to begin with. And the second is to add a comment so
the reader understands without even having to analyse the code
why they are there. If your boss disagrees with either of these
solutions, the case is hopeless.

--
James Kanze

Francis Glassborow

unread,
Nov 29, 2010, 8:15:49 PM11/29/10
to

I think VC++ has been doing that for over a decade. It isn't even
difficult when the code is something like a minimal access function.

Compiler technology has moved on a great deal over the last two decades.
That is actually part of the problem because it sometimes has moved too
far. IIRC IBM had trouble with its C++ implementation because it was
aggressively using a code repository which resulted in breaking some of
the scoping rules. Sometimes separate compilation is essential if C++
(and C) code is to work as intended.

Francis Glassborow

unread,
Nov 29, 2010, 8:16:41 PM11/29/10
to

And now you have a different problem, getting your editor to understand
the mismatched braces :)

If only managers would understand that the general guideline to minimise
comments is exactly so that those that are left stand out. Anytime there
is no reasonable way to express your intent clearly in code that can be
understood by idiots, is time for an all uppercase comment along the
lines of:

// IF YOU DO NOT UNDERSTAND MY CODE LEAVE IT ALONE

:)

Miles Bader

unread,
Nov 30, 2010, 5:31:22 AM11/30/10
to
James Kanze <james...@gmail.com> writes:
> Ideally, all code should be simple enough to be understood without
> comments, but practically, code solving a complicated problem will
> require some complexity somewhere.

Yeah; sometimes (often?) there are subtle-but-important points which
simply aren't reflected explicitly in the code, and realistically never
will be.

But sadly, many people (like this guy's boss I guess) seem to treat
concepts like "code must be completely understandable without comments"
as dogma rather than one of many tools in the toolbox for making better
code -- i.e., they're using it as an excuse to _not think_...

-Miles

--
The car has become... an article of dress without which we feel uncertain,
unclad, and incomplete. [Marshall McLuhan, Understanding Media, 1964]

Martin B.

unread,
Nov 30, 2010, 7:17:43 AM11/30/10
to

On 30.11.2010 02:15, Francis Glassborow wrote:
> On 29/11/2010 19:29, Martin B. wrote:
>> On 29.11.2010 10:57, Goran wrote:
>>>
>>> On Nov 27, 8:13 pm, "Martin B."<0xCDCDC...@gmx.at> wrote:
>>>> [...]
>>>> For example, in the above snippet, unless SynchronizedPart is marked
>>>> as static
>>>> or enclosed in an anonymous namespace, the compiler/optimizer should
>>>> assume
>>>> external linkage and as such will treat this function no differently
>>>> than any
>>>> other function, no matter how often it's used.
>>> [...]
>>>
>>> I actually disagree with external linkage part. Compilers both can and
>>> will inline the function even when it has external linkage. I was
>>> surprised when I first saw that, but now I know they do it, and it's a
>>> good thing :-) .
>>>
>>
>> Which compiler? Which options? Which platform? Which version?
>
> I think VC++ has been doing that for over a decade. It isn't even
> difficult when the code is something like a minimal access function.
>
> [...]

Since I specifically stated the opposite in the part of my reply you
snipped, I would be interested if you could further clarify under which
circumstances VC++ (2005 - 2010) would inline a function that is *not*
marked inline (in *the absence* of whole program optimization).

That is,
-----
foo.h
-----
struct X {
int x_;
int get();
};

int access(X const& obj);

-------
foo.cpp
-------
int X::get() {
return x_;
}

int access(X const& obj) {
return obj.x_;
}

I expect neither `X::get` nor `access` to be inlined.

cheers,
Martin

Martin Bonner

unread,
Nov 30, 2010, 9:49:28 PM11/30/10
to
On Nov 30, 12:17 pm, "Martin B." <0xCDCDC...@gmx.at> wrote:
> Since I specifically stated the opposite in the part of my reply you
> snipped, I would be interested if you could further clarify under which
> circumstances VC++ (2005 - 2010) would inline a function that is *not*
> marked inline (in *the absence* of whole program optimization).

When you ask it to. Specifically /Ob2 which is documented as:

"Expands functions marked as inline or __inline
and any other function that the compiler chooses"

Note the "any other function that the compiler chooses".

... and I think that option has been present for something like the
decade that Francis refers to.

Daniel James

unread,
Nov 30, 2010, 9:49:01 PM11/30/10
to
In article <ZeudnWUPbO38B2_R...@bt.com>, Francis Glassborow wrote:
> Well if you really want something other than comments to stop idiots
> breaking your code then
>
> bool just_once(false);
> do {
> // place your code here
> } while(just_once);
>
> Though i think that is awful :)

Perhaps the message is better conveyed by:

const bool object_lifetimes_matter(true);

if( object_lifetimes_matter )
{
// place code here
}

Still fairly awful, but at least it offers some education to code
reviewers to who might otherwise be tempted to break the code by
removing the braces!

It's self-commenting, and won't impose any runtime overhead as the
compiler can easily optimize it away ... the biggest problem is that
some fool may decide that object lifetimes don't matter and change the
initialization of the bool, effectively removing the whole code block
from the program.

Cheers,
Daniel.


--

Francis Glassborow

unread,
Nov 30, 2010, 9:52:27 PM11/30/10
to
On 30/11/2010 12:17, Martin B. wrote:
>
> Since I specifically stated the opposite in the part of my reply you
> snipped, I would be interested if you could further clarify under which
> circumstances VC++ (2005 - 2010) would inline a function that is *not*
> marked inline (in *the absence* of whole program optimization).
>
> That is,
> -----
> foo.h
> -----
> struct X {
> int x_;
> int get();
> };
>
> int access(X const& obj);
>
> -------
> foo.cpp
> -------
> int X::get() {
> return x_;
> }
>
> int access(X const& obj) {
> return obj.x_;
> }
>
> I expect neither `X::get` nor `access` to be inlined.
>
> cheers,
> Martin

IIRC microsoft called small functions 'intrinsics' The point is that if
the code takes less space than a function call it could drop the code in
as a replacement and add a couple of no-ops if necessary. And that is
always possible for sufficiently small code.

hak...@gmail.com

unread,
Nov 30, 2010, 10:05:27 PM11/30/10
to
On Nov 29, 8:15 pm, Francis Glassborow
<francis.glassbo...@btinternet.com> wrote:

> >> I actually disagree with external linkage part. Compilers both can and
> >> will inline the function even when it has external linkage. I was
> >> surprised when I first saw that, but now I know they do it, and it's a
> >> good thing :-) .
>
> > Which compiler? Which options? Which platform? Which version?
>
> I think VC++ has been doing that for over a decade. It isn't even
> difficult when the code is something like a minimal access function.

GCC offers a flag -flto (link-time optimization) that i think is
supposed to do this, but my testing (see below) seems to show it does
not work, even for simple functions. At first i thought i'd just look
at the assembly, but i gcc doesn't link files when it prints assembly,
not even with the -flto option. So, then i thought i'd use gdb. If i
can set a breakpoint at a function, it must have been called, not
inlined, and alas, i found this was the case for even a simple
function with external linkage.

It seems this feature is (or at least was) controversial for GCC since
there's an issue with exposing its internal representation. Too off
topic to get in to now, but the feature is still listed as unsupported
of Gentoo Linux.

I would be interested if there were any other widely available
compilers that do this, or whether we can only depend on it on the
Windows platform, when using VC++.

My test:
test$ cat main.cpp
#include <iostream>
using namespace std;

#include "include.h"

int will_inline()
{
return 25;
}

int main( int argc, char** argv )
{
cout << will_inline() << will_not_inline();
}
test$ cat include.h
#pragma once

int will_not_inline();
test$ cat include.cpp

#include "include.h"

int will_not_inline()
{
return 1;
}
test$ g++ -c -flto include.cpp -o inc.o
test$ g++ -flto main.cpp inc.o -o run
test$ cp run ~/run
test$ gdb ~/run
GNU gdb (Gentoo 7.2 p1) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/
gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show
copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.gentoo.org/>...
Reading symbols from /home/scott/run...(no debugging symbols
found)...done.
(gdb) break will_inline()
Breakpoint 1 at 0x8048607
(gdb) break will_not_inline()
Breakpoint 2 at 0x804866c
(gdb) run
Starting program: /home/scott/run
Traceback (most recent call last):
File "/usr/share/gdb/auto-load/usr/lib/gcc/i686-pc-linux-gnu/4.5.1/
libstdc++.so.6.0.14-gdb.py", line 59, in <module>
from libstdcxx.v6.printers import register_libstdcxx_printers
ImportError: No module named libstdcxx.v6.printers

Breakpoint 2, 0x0804866c in will_not_inline() ()
(gdb) q
A debugging session is active.

Inferior 1 [process 15578] will be killed.

Quit anyway? (y or n) y
test$ g++ -v
Using built-in specs.
COLLECT_GCC=/usr/i686-pc-linux-gnu/gcc-bin/4.5.1/g++
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/i686-pc-linux-gnu/4.5.1/lto-
wrapper
Target: i686-pc-linux-gnu
Configured with: /var/tmp/portage/sys-devel/gcc-4.5.1-r1/work/
gcc-4.5.1/configure --prefix=/usr --bindir=/usr/i686-pc-linux-gnu/gcc-
bin/4.5.1 --includedir=/usr/lib/gcc/i686-pc-linux-gnu/4.5.1/include --
datadir=/usr/share/gcc-data/i686-pc-linux-gnu/4.5.1 --mandir=/usr/
share/gcc-data/i686-pc-linux-gnu/4.5.1/man --infodir=/usr/share/gcc-
data/i686-pc-linux-gnu/4.5.1/info --with-gxx-include-dir=/usr/lib/gcc/
i686-pc-linux-gnu/4.5.1/include/g++-v4 --host=i686-pc-linux-gnu --
build=i686-pc-linux-gnu --disable-altivec --disable-fixed-point --
without-ppl --without-cloog --enable-lto --disable-nls --with-system-
zlib --disable-werror --enable-secureplt --disable-multilib --enable-
libmudflap --disable-libssp --enable-libgomp --enable-cld --with-
python-dir=/share/gcc-data/i686-pc-linux-gnu/4.5.1/python --enable-
checking=release --enable-java-awt=gtk --with-arch=i686 --enable-
languages=c,c++,java --enable-shared --enable-threads=posix --enable-
__cxa_atexit --enable-clocale=gnu --with-bugurl=http://
bugs.gentoo.org/ --with-pkgversion='Gentoo 4.5.1-r1 p1.3, pie-0.4.5'
Thread model: posix
gcc version 4.5.1 (Gentoo 4.5.1-r1 p1.3, pie-0.4.5)

> Compiler technology has moved on a great deal over the last two decades.

I don't think the issue is technology but availability. It seems like
people sometimes come on here thinking "my compiler supports feature X
and it seems standard, so everyone has access to feature X!".

Öö Tiib

unread,
Nov 30, 2010, 10:03:27 PM11/30/10
to
On Nov 30, 3:16 am, Francis Glassborow

<francis.glassbo...@btinternet.com> wrote:
>
> If only managers would understand that the general guideline to minimise
> comments is exactly so that those that are left stand out. Anytime there
> is no reasonable way to express your intent clearly in code that can be
> understood by idiots, is time for an all uppercase comment along the
> lines of:
>
> // IF YOU DO NOT UNDERSTAND MY CODE LEAVE IT ALONE
>
> :)

That is too radical. ;) There are different levels of understanding.
For example some usual piece of code. Most readers understand what it
does if naming is not cryptic or misleading. On most cases the
misunderstanding is because reader does not understand why it does
that in the way it does.

For example "why updating shared data is unconditional?", "why the
scoped lock needs to unlock in middle of function not at end?" or "why
the scope that unconditionally updates shared data is not useful as
separate function?". At least something of it might be perhaps hard to
understand from OP's example.

Andre Kaufmann

unread,
Nov 30, 2010, 10:02:56 PM11/30/10
to
On 30.11.2010 13:17, Martin B. wrote:
> [...]

>
> I expect neither `X::get` nor `access` to be inlined.

I suppose get() will be inlined (if it's called in the same compilation
unit).

If you don't use the >restriction< no global optimization and activate
(which is by default activated) global optimization/link time code
generation all functions will be inlined.

Additionally if you use a wrapper function to handle the code part to be
locked, I would assume it to be nearby the function calling it.
Therefore it will be inline in most of the cases.


Back to a comparable C# using example, which is also a good example of
C++ compiler optimization:

As mentioned in other posts lambda functions could be used, to simulate
the C# using syntax:

For the ones which are not familiar with C#: Keyword >using< is some
kind of C# RAII:

void foo()
{
using (Object o = new Object())
{
} // end of block
}

Ensures, that o.Dispose() is called at the end of the block or if an
exception occurs. Dispose() can be "roughly compared" to a kind of
resource-destructor (doesn't free memory however).


This could be simulated in C++
(similar examples have been already posted)

E.g.:

#include <functional>

class Mutex
{
public:
void Lock() { printf("Locked\r\n"); }
void Unlock() { printf("Unlocked\r\n"); }
};

class AutoLock
{
public:
AutoLock (Mutex& mInit) : m(mInit) { m.Lock(); }
~AutoLock() { m.Unlock(); }


Mutex& m;
};


template<typename F>
void LockScope(Mutex& m, const F& call) { AutoLock a(m); call(); }

int main(int argc, char* argv[])
{
Mutex mutex;

LockScope(mutex, []()
{
printf("DoStuff");
});
return 0;
}


The C++ compiler (in this case VC++ default release config settings)
optimizes and compiles this code to the equivalent of:

printf("Locked");
printf("DoStuff");
printf("Unlocked");


> cheers,
> Martin

Andre

Martin B.

unread,
Dec 1, 2010, 7:25:34 AM12/1/10
to

On 01.12.2010 04:02, Andre Kaufmann wrote:
> On 30.11.2010 13:17, Martin B. wrote:
>> [...]
>>
>> I expect neither `X::get` nor `access` to be inlined.
>
> I suppose get() will be inlined (if it's called in the same compilation
> unit).
>

Ah! You raise an important point. The compiler could be free to inline a
function in one translation unit and still create a function to be used
from another translation unit. Correct?

> If you don't use the >restriction< no global optimization and activate
> (which is by default activated) global optimization/link time code
> generation all functions will be inlined.
>

Blanket statement! Though I assume by *all* you meant my two functions
from my post :-)

Note, that all other inlining restrictions still apply. (Such as, if the
function contains a try-catch block it will not be inlined in VC++.)

> Additionally if you use a wrapper function to handle the code part to be
> locked, I would assume it to be nearby the function calling it.
> Therefore it will be inline in most of the cases.
>

What is "nearby" supposed to mean here? It certainly would be in the
same translation unit, but I guess it wouldn't matter *where* in the
same translation unit?

cheers,
Martin

Martin B.

unread,
Dec 1, 2010, 7:25:58 AM12/1/10
to

On 01.12.2010 03:49, Martin Bonner wrote:
> On Nov 30, 12:17 pm, "Martin B."<0xCDCDC...@gmx.at> wrote:
>> Since I specifically stated the opposite in the part of my reply you
>> snipped, I would be interested if you could further clarify under which
>> circumstances VC++ (2005 - 2010) would inline a function that is *not*
>> marked inline (in *the absence* of whole program optimization).
>
> When you ask it to. Specifically /Ob2 which is documented as:
>
> "Expands functions marked as inline or __inline
> and any other function that the compiler chooses"
>
> Note the "any other function that the compiler chooses".
>
> .... and I think that option has been present for something like the

> decade that Francis refers to.
>

Well we use /Ob2, but I've never seen the compiler inline a function
with external linkage. (I admit, I haven't looked especially hard.)

Would be interesting to see an example of this actually happening.

cheers,
Martin

Andy Venikov

unread,
Dec 3, 2010, 1:02:49 AM12/3/10
to
On 11/30/2010 10:05 PM, Hak...@gmail.com wrote:

<snip>

> GCC offers a flag -flto (link-time optimization) that i think is
> supposed to do this, but my testing (see below) seems to show it does
> not work, even for simple functions. At first i thought i'd just look
> at the assembly, but i gcc doesn't link files when it prints assembly,
> not even with the -flto option. So, then i thought i'd use gdb. If i
> can set a breakpoint at a function, it must have been called, not
> inlined, and alas, i found this was the case for even a simple
> function with external linkage.
>

Link Time Optimization (or whole-program optimization in Microsoft terms) by
itself will not trigger inlining of non-inline functions. It will only broaden
the scope of where the inlining will be done. The decision to do that or not is
triggered by a compiler switch -finline-functions, which is enabled by default
at optimization level -O3

Andy.

Andy Venikov

unread,
Dec 3, 2010, 1:01:03 AM12/3/10
to
On 11/29/2010 2:29 PM, Martin B. wrote:

<snip>


>
> Otherwise I do not see how it could make sense for a *compiler* to
> inline a function *not marked* as inline if it has to expect the fn to
> be used (by the linker) from another translation unit.
>

Judging by this statement I think you may be erroneously assuming that the
requirement that the function body be generated precludes it from being inlined.

Having to generate a body for a function in no way restricts the compiler from
inlining this function in places where it makes sense.


Andy.

Andre Kaufmann

unread,
Dec 3, 2010, 1:39:07 PM12/3/10
to
On 01.12.2010 13:25, Martin B. wrote:
>
> [...]

> Ah! You raise an important point. The compiler could be free to inline a
> function in one translation unit and still create a function to be used
> from another translation unit. Correct?

I think so, that the compiler is free to do that.
But I don't know if it is free or better said can to do that if global
optimization is deactivated. E.g. if the address is taken, it cannot
(shouldn't) inline the function (in neither translation unit).

> [...]


> Blanket statement! Though I assume by *all* you meant my two functions
> from my post :-)

Yes - inlining all functions in an applications would result into
bloatware, or a really, really big main(...) function ;-)

>
> Note, that all other inlining restrictions still apply. (Such as, if the
> function contains a try-catch block it will not be inlined in VC++.)

Why can't they be inlined ? Or do you mean if two different exception
models are used ? Then yes.
However there are plenty of other restrictions, virtual functions
(indirect call), variable arguments etc.

> [...]


> What is "nearby" supposed to mean here?

It doesn't matter for the compiler, but I think it's better to have such
small helper functions on the screen with the function calling it.
(it's just a matter of my personal taste and depends of the size and
amount of helper functions)

> It certainly would be in the
> same translation unit, but I guess it wouldn't matter *where* in the
> same translation unit?

Sure - I just wondered why you declared the "helper" functions in the
header file in your example.

> cheers,
> Martin

Cheers Andre

Andre Kaufmann

unread,
Dec 3, 2010, 1:39:56 PM12/3/10
to
On 01.12.2010 04:05, Hak...@gmail.com wrote:
> On Nov 29, 8:15 pm, Francis Glassborow

> I would be interested if there were any other widely available


> compilers that do this, or whether we can only depend on it on the
> Windows platform, when using VC++.

AFAIK the Intel C++ compiler has global optimization as well.
(I freely available for Linux IIRC, however I don't think it supports
other than x86/Itanium/x64 based CPUs)

Andre

Andre Kaufmann

unread,
Dec 3, 2010, 1:41:16 PM12/3/10
to
On 01.12.2010 13:25, Martin B. wrote:
> [...]
>
> Well we use /Ob2, but I've never seen the compiler inline a function
> with external linkage. (I admit, I haven't looked especially hard.)

/LTCG (Link time code generation) is also needed for inlining functions
with external linkage.


> Would be interesting to see an example of this actually happening.

Just call a small member function (once) from another translation unit.
And it should be inlined if global optimization/link time code
generation is on. (results may be perhaps influenced by the other
optimization settings - e.g. optimize for size / speed etc.).

> cheers,
> Martin


Andre

Martin B.

unread,
Dec 6, 2010, 12:18:25 PM12/6/10
to
On 03.12.2010 19:39, Andre Kaufmann wrote:
> On 01.12.2010 13:25, Martin B. wrote:
>>
>> Note, that all other inlining restrictions still apply. (Such as, if the
>> function contains a try-catch block it will not be inlined in VC++.)
>
> Why can't they be inlined ? Or do you mean if two different exception
> models are used ? Then yes.

I mean what I wrote. If a function contains a try-catch block, VC++ (2010) will
never, ever, inline it.
See:
http://msdn.microsoft.com/en-us/library/a98sb923%28v=VS.100%29.aspx

Compiler Warning (level 4) C4714
... the compiler will not inline a
particular function for mechanical reasons ...
* A function with a try (C++ exception handling) statement.


>> [...]
>> What is "nearby" supposed to mean here?
>
> It doesn't matter for the compiler, but I think it's better to have such
> small helper functions on the screen with the function calling it.
> (it's just a matter of my personal taste and depends of the size and
> amount of helper functions)
>
>> It certainly would be in the
>> same translation unit, but I guess it wouldn't matter *where* in the
>> same translation unit?
>
> Sure - I just wondered why you declared the "helper" functions in the
> header file in your example.
>

Oh yes. The declaration of int access(X const& obj) in my sample code was
superfluous. A simple helper would not be declared in the header - still, its
linkage would be external regardless. (But we could define it inline which would
help the compiler to inline it.)

cheers,
Martin

Bart van Ingen Schenau

unread,
Dec 7, 2010, 6:09:20 PM12/7/10
to
On Dec 3, 7:39 pm, Andre Kaufmann <akfmn...@t-online.de> wrote:
> On 01.12.2010 13:25, Martin B. wrote:
>
> > [...]
> > Ah! You raise an important point. The compiler could be free to inline a
> > function in one translation unit and still create a function to be used
> > from another translation unit. Correct?
>
> I think so, that the compiler is free to do that.
> But I don't know if it is free or better said can to do that if global
> optimization is deactivated. E.g. if the address is taken, it cannot
> (shouldn't) inline the function (in neither translation unit).

Even then, the compiler is allowed to perform inline expansion of the
function in those TU's where the definition is visible. The compiler
just has to be extra careful with local variables with static
lifetime, because a conforming application may not be able to tell if
inline expansion took place or not.

The two requirements for inline expansion are:
- If it took place or not must be transparent to the application. Even
if it takes the address of the function or if the function contains
static variables.
- The compiler must keep a non-inline copy of the function if the
address was taken or if there might be external references not visible
to the compiler at that time.

<snip>


>
> > Note, that all other inlining restrictions still apply. (Such as, if the
> > function contains a try-catch block it will not be inlined in VC++.)
>
> Why can't they be inlined ?

This is not a general limitation, but it seems to stem from the way VC+
+ originally implemented the try-catch mechanism.

Bart v Ingen Schenau

0 new messages