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

Re: Pointer declarations

78 views
Skip to first unread message

Chris Vine

unread,
Nov 25, 2017, 8:19:31 AM11/25/17
to
On 25 Nov 2017 12:43:44 GMT
r...@zedat.fu-berlin.de (Stefan Ram) wrote:
> Which style is better for a pointer declaration:
>
> A:
>
> { auto i { 4 };
> auto p { &i };
> /* ... */ }
>
> or B:
>
> { auto i { 4 };
> auto * p { &i };
> /* ... */ }

'int * p = &i'. If you are passing pointers around, in my view it is
better explicitly to declare its type.

Mr Flibble

unread,
Nov 25, 2017, 11:52:26 AM11/25/17
to
And more to the point:

int i = 4;

not fucking:

auto i { 4 };

which is borderline mental.

/Flibble


Mr Flibble

unread,
Nov 25, 2017, 11:55:00 AM11/25/17
to
And even better:

int_fast32_t i = 4;

if you want a fast integer with at least 32 bits.

/Flibble

Vir Campestris

unread,
Nov 25, 2017, 4:30:39 PM11/25/17
to
On 25/11/2017 13:19, Chris Vine wrote:
> If you are passing pointers around, in my view it is
> better explicitly to declare its type.

My view too. Use auto only when you must (eg lambdas).

In my old company that was a coding standard.

Andy

Mr Flibble

unread,
Nov 25, 2017, 6:03:27 PM11/25/17
to
Using auto for the return value of a function call is fine but using
auto to initialize from a value literal is just mental.

/Flibble

Ian Collins

unread,
Nov 25, 2017, 6:05:54 PM11/25/17
to
It is that. A bit like using suffix return for main :)

--
Ian

Gareth Owen

unread,
Nov 26, 2017, 1:51:02 AM11/26/17
to
Vir Campestris <vir.cam...@invalid.invalid> writes:

> On 25/11/2017 13:19, Chris Vine wrote:
>> If you are passing pointers around, in my view it is
>> better explicitly to declare its type.
>
> My view too. Use auto only when you must (eg lambdas).

How do you feel about using it for loop variables:

for(auto it = foo.begin(); it foo.end(); ++i) {}

or

for(const auto& x : xvec) {}

Jorgen Grahn

unread,
Nov 26, 2017, 3:26:36 AM11/26/17
to
On Sat, 2017-11-25, Vir Campestris wrote:
> On 25/11/2017 13:19, Chris Vine wrote:
>> If you are passing pointers around, in my view it is
>> better explicitly to declare its type.
>
> My view too.

Note that your view is more radical, since you then add:

> Use auto only when you must (eg lambdas).
>
> In my old company that was a coding standard.

At the other extreme, I think it was Herb Sutter who claimed we should
use auto as much as possible -- and get special tools which can tell
us what types our variables /really/ have.

Personally, I use auto, but only where I think it makes the code
clearer. That ends up as maybe 20--50% of the places where I /could/
have squeezed in an auto.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Chris Vine

unread,
Nov 26, 2017, 10:11:25 AM11/26/17
to
On 26 Nov 2017 08:26:13 GMT
Jorgen Grahn <grahn...@snipabacken.se> wrote:
> On Sat, 2017-11-25, Vir Campestris wrote:
> > On 25/11/2017 13:19, Chris Vine wrote:
> >> If you are passing pointers around, in my view it is
> >> better explicitly to declare its type.
> >
> > My view too.
>
> Note that your view is more radical, since you then add:
>
> > Use auto only when you must (eg lambdas).
> >
> > In my old company that was a coding standard.
>
> At the other extreme, I think it was Herb Sutter who claimed we should
> use auto as much as possible -- and get special tools which can
> tell us what types our variables /really/ have.

New features seem to get overhyped like this. While type inference
with the auto keyword is nifty in shortening code, its downside (apart
from making things less obvious for the reader) is that it can separate
the location of a type error from the place in the code where the error
is likely to be first detected. Extending the circumstances in which
you get incomprehensible template-like error messages is not an
advantage in my view. The auto keyword is I think best used in small
local block scopes where the possibility for error reporting
displacement of this kind doesn't really arise.

For that reason, even languages that use, say, the more complete
Hindley-Milner type inference system tend to recommend that, where a
function does not employ parametric polymorphism (aka templates in C++)
then its arguments should be explicitly typed except where the function
is a very simple one. That makes type errors much easier to deal with.

> Personally, I use auto, but only where I think it makes the code
> clearer. That ends up as maybe 20--50% of the places where I /could/
> have squeezed in an auto.

Ditto.

Vir Campestris

unread,
Nov 26, 2017, 4:28:52 PM11/26/17
to
On 26/11/2017 06:50, Gareth Owen wrote:
> How do you feel about using it for loop variables:
>
> for(auto it = foo.begin(); it foo.end(); ++i) {}

Is that an iterator or a const_iterator?
>
> or
>
> for(const auto& x : xvec) {}

There's no need to do it here either.

The problem in the absence of really clever tools (1)(2) is that the
casual reader can't tell at a glance what x really is. And even when the
tools are working you usually have to "hover" on the variable, then
wait, to see. Which is slower.

Andy

1)I used to use MSVC, and that was clever enough; I haven't found one
for Linux
2) I don't always agree with Herb. Nearly always, but not every time!

Gareth Owen

unread,
Nov 26, 2017, 5:32:48 PM11/26/17
to
Vir Campestris <vir.cam...@invalid.invalid> writes:

> On 26/11/2017 06:50, Gareth Owen wrote:
>> How do you feel about using it for loop variables:
>>
>> for(auto it = foo.begin(); it foo.end(); ++i) {}
>
> Is that an iterator or a const_iterator?

If you know what the type of foo, that will tell you that whether you
can mutate its elements. If know the const-ness of the container,
there's no benefit to knowing the (name of the) type of the iterator,

And if you don't know the constness of the container, you can't even
write the non-auto version.

>>
>> or
>>
>> for(const auto& x : xvec) {}
>
> There's no need to do it here either.

There's almost never a need to do it at all. As proven by every C++
prior to C++11

> The problem in the absence of really clever tools (1)(2) is that the
> casual reader can't tell at a glance what x really is.

It's "an iterator to the type of the container" or "a reference to an
item in the container."

> And even when the tools are working you usually have to "hover" on the
> variable, then wait, to see. Which is slower.

Mostly, though, you simply never need to know the exact type of an
iterator - just that you can iterate with it. That's why they're a good
abstraction[0].

"Something I can use to iterate" is all the programmer needs to know.

[0] And any way, mostly they're opaque anyway. We know
std::vector<T>::iterator is probably a T*, but everything else is
implementation defined.

Vir Campestris

unread,
Nov 26, 2017, 5:43:45 PM11/26/17
to
On 26/11/2017 22:32, Gareth Owen wrote:
> Mostly, though, you simply never need to know the exact type of an
> iterator - just that you can iterate with it. That's why they're a good
> abstraction[0].

I bet you put your curly brackets in the wrong place too... :)

Andy

Alf P. Steinbach

unread,
Nov 27, 2017, 2:20:55 AM11/27/17
to
On 11/26/2017 10:28 PM, Vir Campestris wrote:
> On 26/11/2017 06:50, Gareth Owen wrote:
>> How do you feel about using it for loop variables:
>>
>> for(auto it = foo.begin(); it  foo.end(); ++i) {}
>
> Is that an iterator or a const_iterator?

Explicitly writing out the iterator type can be verbose and brittle, and
so I wouldn't do that, but the question of how to communicate the
constness of the iterator's referent is interesting.

Well it wouldn't be interesting if the iterator referent constness was
always apparent from the constness of the collection. But e.g. with a
`std::set` the iterator referent (set item) is `const` regardless of the
constness of the set itself. And the other way, a `const` collection
producing iterators with non-`const` referents, can also, at least in
principle, occur, e.g. when the collection is a begin/end-pair proxy for
accessing items of some other collection.

When the loop can be expressed as a range based loop one can easily
communicate and enforce constness of the items:

for( auto const& item : foo ) //...

The other way can also easily be communicated,

for( auto& mutable_item : foo )

… but not so easily enforced:

for( auto& mutable_item : foo )
{
static_assert( not is_const_v<remove_reference_t<decltype(
mutable_item )>> );
//...
}

To help with enforcement one may therefore define e.g.

template< class Type >
void assert_is_mutable( Type& )
{
static_assert( not is_const_v<Type>, "The object must be
mutable" );
}

… and then write

for( auto& item : foo )
{
assert_is_mutable( item );
//...
}

The last approach works also for the original problem, by defining

template< class Type >
void assert_is_const( Type& )
{
static_assert( is_const_v<Type>, "The object must const" );
}

… and then writing

for( auto it = foo.begin(); it != foo.end(); ++it )
{
assert_is_const( *it );
//...
}

Doing this instead as expressions fed to `static_assert` runs into
problems. I think it would be nice if a call of a `constexpr` function F
with an actual argument that involved a call of a non-`constexpr`
function, could yield a `constexpr` result when only the type of the
actual argument was used to produce the result (or perhaps simpler, if
the formal argument in F was not named). This could solve :-) also the
problem with C++17 `std::size`, which can't formally be applied to a
formal argument array reference, which IMHO is just über-silly.


>> or
>>
>> for(const auto& x : xvec) {}
>
> There's no need to do it here either.
>
> The problem in the absence of really clever tools (1)(2) is that the
> casual reader can't tell at a glance what x really is. And even when the
> tools are working you usually have to "hover" on the variable, then
> wait, to see. Which is slower.

Much of the point is that one really doesn't care about the exact type
of an iterator, and that it's desirable to /not/ know, because using
that knowledge just makes the code brittle and possibly non-portable.


> [snip]
> 2) I don't always agree with Herb. Nearly always, but not every time!

NAAAH - Nearly Almost Always Auto, Herb.


Cheers!,

- Alf

Gareth Owen

unread,
Nov 27, 2017, 2:28:01 PM11/27/17
to
#define BEGIN {
#define END }

...

Manfred

unread,
Nov 28, 2017, 8:43:37 AM11/28/17
to
On 11/27/2017 8:20 AM, Alf P. Steinbach wrote:
> On 11/26/2017 10:28 PM, Vir Campestris wrote:
>> On 26/11/2017 06:50, Gareth Owen wrote:
>>> How do you feel about using it for loop variables:
>>>
>>> for(auto it = foo.begin(); it  foo.end(); ++i) {}
>>
>> Is that an iterator or a const_iterator?
>
> Explicitly writing out the iterator type can be verbose and brittle, and
> so I wouldn't do that, but the question of how to communicate the
> constness of the iterator's referent is interesting.
>

[snip]

>
>     for( auto& item : foo )
>     {
>         assert_is_mutable( item );
>         //...
>     }
>
> The last approach works also for the original problem, by defining
>
>     template< class Type >
>     void assert_is_const( Type& )
>     {
>         static_assert( is_const_v<Type>, "The object must const" );
>     }
>
> … and then writing
>
>     for( auto it = foo.begin(); it != foo.end(); ++it )
>     {
>         assert_is_const( *it );
>         //...
>     }

For this original problem, an even simpler writing would directly use
cbegin() and cend().

[snip]

>> The problem in the absence of really clever tools (1)(2) is that the
>> casual reader can't tell at a glance what x really is. And even when
>> the tools are working you usually have to "hover" on the variable,
>> then wait, to see. Which is slower.
>
> Much of the point is that one really doesn't care about the exact type
> of an iterator, and that it's desirable to /not/ know, because using
> that knowledge just makes the code brittle and possibly non-portable.
>
Indeed.

0 new messages