Saturday, June 13, 2015

Digest for comp.lang.c++@googlegroups.com - 25 updates in 5 topics

Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 13 05:43PM +0100

In modern C++ we should avoid using 'int' and its associates such as
'short' and 'long' as they are all non-portable and unsafe (their size
and value range can differ from one implementation to the next); instead
one should use the typedefs from <cstdint> instead.
 
A consequence of this rule is that we must never use 'auto' with integer
literals such as:
 
auto i = 42;
 
or
 
auto i = 42u;
 
instead we write:
 
int32_t i = 42;
 
or
 
uint32_t i = 42u;
 
The fact we have to do this is due to shortcoming of the current C++
Standard; what we need is something like:
 
auto i = 42s32; // signed, 32-bits
 
or
 
auto i = 42u32; // unsigned, 32-bits
 
/Flibble
Bo Persson <bop@gmb.dk>: Jun 13 07:57PM +0200

On 2015-06-13 18:43, Mr Flibble wrote:
 
> auto i = 42s32; // signed, 32-bits
 
> or
 
> auto i = 42u32; // unsigned, 32-bits
 
Why?
 
The type int is available on ALL systems, and guaranteed to be able to
hold the value 42. int32_t is not available on systems lacking a 32-bit
two's complement type. Thus slightly less portable.
 
 
Bo Persson
gwowen <gwowen@gmail.com>: Jun 13 10:59AM -0700

On Saturday, June 13, 2015 at 5:43:06 PM UTC+1, Mr Flibble wrote:
> ....
> instead we write:
 
> int32_t i = 42;
 
Nothing says "portable" like using a type that is explicitly marked as "optional".
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 13 07:05PM +0100

On 13/06/2015 18:59, gwowen wrote:
>> instead we write:
 
>> int32_t i = 42;
 
> Nothing says "portable" like using a type that is explicitly marked as "optional".
 
Portable does not mean "compilable on all known platforms"; portable
means that code runs *correctly* as-is on all platforms for which it
compiles.
 
/Flibble
Luca Risolia <luca.risolia@linux-projects.org>: Jun 13 08:06PM +0200

Il 13/06/2015 18:43, Mr Flibble ha scritto:
> auto i = 42;
 
> instead we write:
 
> int32_t i = 42;
 
Why must one reserve 32bits for 42, if it can be stored in an int which
is, say, 16bit long?
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 13 07:06PM +0100

On 13/06/2015 18:57, Bo Persson wrote:
 
> The type int is available on ALL systems, and guaranteed to be able to
> hold the value 42. int32_t is not available on systems lacking a 32-bit
> two's complement type. Thus slightly less portable.
 
Because the type of 42 is 'int' and 'int' is unsafe and must not be
used. See my other reply for why you misunderstand what we mean by
"portable".
 
/Flibble
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 13 07:07PM +0100

On 13/06/2015 19:06, Luca Risolia wrote:
 
>> int32_t i = 42;
 
> Why must one reserve 32bits for 42, if it can be stored in an int which
> is, say, 16bit long?
 
You can also use int16_t.
 
/Flibble
Luca Risolia <luca.risolia@linux-projects.org>: Jun 13 08:10PM +0200

Il 13/06/2015 20:07, Mr Flibble ha scritto:
> You can also use int16_t.
 
Exactly, I can also use whatever auto gives me.
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 13 07:11PM +0100

On 13/06/2015 19:10, Luca Risolia wrote:
> Il 13/06/2015 20:07, Mr Flibble ha scritto:
>> You can also use int16_t.
 
> Exactly, I can also use whatever auto gives me.
 
No as doing so is unsafe as I have shown in my other replies.
 
/Flibble
Ben Bacarisse <ben.usenet@bsb.me.uk>: Jun 13 07:21PM +0100


> In modern C++ we should avoid using 'int' and its associates such as
> 'short' and 'long' as they are all non-portable and unsafe (their size
> and value range can differ from one implementation to the next);
 
That's a overstatement. Where the minimum guaranteed rage is adequate,
using these types is neither non-portable nor unsafe. (They can, of
course, be *used* in unsafe and non-portable ways but it's hard to think
of type that can't be so abused.)
 
<snip>
> instead we write:
 
> int32_t i = 42;
 
In most cases int_least32_t is a better choice. It's mandatory, and
will be the same as int32_t where such a type exists.
 
<snip>
--
Ben.
gwowen <gwowen@gmail.com>: Jun 13 11:22AM -0700

On Saturday, June 13, 2015 at 7:07:42 PM UTC+1, Mr Flibble wrote:
 
> > Why must one reserve 32bits for 42, if it can be stored in an int which
> > is, say, 16bit long?
 
> You can also use int16_t.
 
Except when you can't.
 
Choose a type based on your problem domain. Trying to decide which types are acceptable without reference to the problem domain is utterly idiotic.
 
If you're indexing a list Presidents of the US, you can use int without any portability issues.
 
If you're counting US Govt Debt, you need to be more explicit about the range of the variable.
 
Immutable rules are for people who don't know what they're doing.
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 13 07:27PM +0100

On 13/06/2015 19:22, gwowen wrote:
 
>> You can also use int16_t.
 
> Except when you can't.
 
> Choose a type based on your problem domain. Trying to decide which types are acceptable without reference to the problem domain is utterly idiotic.
 
Using 'int' everywhere is you NOT choosing a type at all; it is just you
not thinking properly about your problem domain so by your own words you
are "idiotic".
 
 
> If you're indexing a list Presidents of the US, you can use int without any portability issues.
 
Wrong; for indexing you should use an unsigned type usually std::size_t
(or container::size_type).
 
 
> If you're counting US Govt Debt, you need to be more explicit about the range of the variable.
 
> Immutable rules are for people who don't know what they're doing.
 
The code you write must be really unsafe; I wouldn't trust it as far as
I could throw it if it was printed on a large rock that I couldn't throw
very far.
 
/Flibble
Luca Risolia <luca.risolia@linux-projects.org>: Jun 13 09:01PM +0200

Il 13/06/2015 18:43, Mr Flibble ha scritto:
 
> auto i = 42s32; // signed, 32-bits
 
> or
 
> auto i = 42u32; // unsigned, 32-bits
 
you are talking about variable templates, aren't you?
 
template<typename T> T I = T(42); // definition
...
auto i = I<std::int32_t>; // use
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 13 08:04PM +0100

On 13/06/2015 20:01, Luca Risolia wrote:
 
> template<typename T> T I = T(42); // definition
> ...
> auto i = I<std::int32_t>; // use
 
No I am not; whatever that is is fugly.
 
/Flibble
Luca Risolia <luca.risolia@linux-projects.org>: Jun 13 09:18PM +0200

Il 13/06/2015 21:04, Mr Flibble ha scritto:
>>> auto i = 42s32; // signed, 32-bits
 
>> you are talking about variable templates, aren't you?
 
> No I am not; whatever that is is fugly.
 
Then what you are saying does not make any sense.
 
Why should the language provide a way to write:
 
auto i = 42s32;
 
if you can already safely initialize i with:
 
std::int32_t i{42};
 
The compiler will produce a diagnostic on narrowing conversions.
Paul <pepstein5@gmail.com>: Jun 13 10:35AM -0700

A C++ textbook says "The string library lets us convert both character literals and character string literals to strings"
 
I don't think I'm included in this "us" because std::string s = 's'; isn't accepted by my compiler. Is this yet another textbook error?
 
Thank You,
 
Paul
Barry Schwarz <schwarzb@dqel.com>: Jun 13 11:07AM -0700

On Sat, 13 Jun 2015 10:35:13 -0700 (PDT), Paul <pepstein5@gmail.com>
wrote:
 
>A C++ textbook says "The string library lets us convert both character literals and character string literals to strings"
 
>I don't think I'm included in this "us" because std::string s = 's'; isn't accepted by my compiler. Is this yet another textbook error?
 
You are trying to do it as initialization. To do that, you need to use
the "fill" form of the constructor since there is no other char form
(see www.cplusplus.com/reference/string/string/string/):
std::string s (1,'s');
 
The operator= has a char form. The conversion works for assignment,
as in:
std::string s;
s = 'x';
 
--
Remove del for email
ram@zedat.fu-berlin.de (Stefan Ram): Jun 13 12:44PM

>const int ci = i
...
>why is auto& g = ci; allowed
 
»A const object is an object« 3.9.3p1.1
ram@zedat.fu-berlin.de (Stefan Ram): Jun 13 12:56PM

>const auto &j = 42; // ok: we can bind a const reference to a literal
 
The reference is /not/ bound to the literal, but to the
/value/ of the literal!
 
Justification:
 
A literal is a part of the source-code model, a value is a
part of the run-time model. A reference is a part of the
run-time model; it can only bind to other run-time entities.
 
Example:
 
const auto &i = 042;
const auto &j = 0042;
 
These are two different literals, but they have the same value.
Where the references bound to the literals, it should be possible
two see the difference between the literals using the references.
But it is not. The reference are bound to the /values/ of the literals,
and the values are the same, so the value of the references also
is the same.
ram@zedat.fu-berlin.de (Stefan Ram): Jun 13 05:51PM

>std::string s = 's'; isn't accepted by my compiler.
 
namespace user
{ namespace std{ struct string{ string( char ){} }; }
void f(){ std::string s = 's'; }} int main() {}
Noob <root@127.0.0.1>: Jun 13 06:28PM +0200

On 13/06/2015 01:30, Ian Collins wrote:
 
 
>> shell 161> g++ -Weffc++ /tmp/a.cpp
 
> A gcc option that breaks google :)
 
> Your search - -Weffc++ - did not match any documents.
 
https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-Options.html#index-Weffc_002b_002b-212
 
-Weffc++ (C++ and Objective-C++ only)
 
Warn about violations of the following style guidelines from Scott Meyers' Effective C++ series of books:
 
Define a copy constructor and an assignment operator for classes with dynamically-allocated memory.
Prefer initialization to assignment in constructors.
Have operator= return a reference to *this.
Don't try to return a reference when you must return an object.
Distinguish between prefix and postfix forms of increment and decrement operators.
Never overload &&, ||, or ,.
 
This option also enables -Wnon-virtual-dtor, which is also one of the effective C++ recommendations. However, the check is extended to warn about the lack of virtual destructor in accessible non-polymorphic bases classes too.
 
When selecting this option, be aware that the standard library headers do not obey all of these guidelines; use 'grep -v' to filter out those warnings.
Noob <root@127.0.0.1>: Jun 13 06:36PM +0200

On 13/06/2015 11:54, Marcel Mueller wrote:
 
> it consists only of built-in data types like int, float, pointer etc. or
> other POD types in all instance attributes and it neither has a custom
> constructor nor private or protected instance attributes.
 
What's a _custom_ constructor?
Is it merely an explicitly defined constructor?
 
 
> To come around the undefined behavior according to the C++ standard you
> can do a trick: split your class into a POD base type and a non POD
> derived type.
 
The objects only contain ints, int arrays, bools, and raw pointers
to other program-defined classes, so it is already POD, AFAIU right?
 
 
> I have used this pattern many times to wrap C APIs more safely by simply
> deriving from their struct types in the C headers. It usually works as
> long as the API let you allocate the storage for the PODs.
 
Thanks, I will look a bit closer at the code.
 
Regards.
Noob <root@127.0.0.1>: Jun 13 07:33PM +0200

On 13/06/2015 11:32, Christian Gollwitzer wrote:
 
> no way to check that for you. For instance, it is not guaranteed even
> for a simple float, that all zero bits denotes 0.0 and not some odd
> value (true for IEEE floats, but...).
 
I'm not sure what you meant by "discards the type information".
 
In C too, it is not guaranteed that all-bits-0 pattern is 0.0 or NULL.
 
> Yes that is right. If you are worried about the amount of code: How do
> you currently initialize your variables? Assign them in the body of the
> constructor? There is a special initialization syntax for constructors:
 
Just to be clear: this is a medium-sized project (100 kLOC) that
someone else wrote for Windows. I am just porting it to Linux,
and a few bugs need fixing along the way. Hopefully, these
fixes are non intrusive! I don't want to rewrite the project.
 
 
> private:
> int value;
> };
 
Your example is nice with 1 field. But the actual definition
is more like this:
 
class foo {
public:
int aa, bb, cc, ...
int va[Na], vb[Nb], ...
int v2a[N2a][Ma], v2b[N2b][Mb], ...
bar *p1, baz *p2, ...
 
foo();
~foo();
40 methods
};
 
Would it still look simple then?
 
 
> private:
> int value = 5;
> };
 
Do g++ and Visual Studio support this syntax?
 
> You could do that for all of your fields at the point where they are
> declared, so would be easy to spot a missing one.
 
Thanks for the suggestion.
 
(However, I'm afraid of the code churn, as it would mean
touching all the class definitions.)
 
Regards.
Paul <pepstein5@gmail.com>: Jun 13 07:31AM -0700

On Saturday, June 13, 2015 at 1:56:22 PM UTC+1, Stefan Ram wrote:
> But it is not. The reference are bound to the /values/ of the literals,
> and the values are the same, so the value of the references also
> is the same.
 
Thanks. The error is in the text I'm quoting from not mine (not that anyone said otherwise).
 
Paul
Paul <pepstein5@gmail.com>: Jun 13 07:37AM -0700

On Saturday, June 13, 2015 at 1:44:42 PM UTC+1, Stefan Ram wrote:
> ...
> >why is auto& g = ci; allowed
 
> »A const object is an object« 3.9.3p1.1
 
Sorry, I still don't get it. The examples below are totally unclear to me. Why is auto &h = 42; wrong? If the answer is because an auto should refer to an object, not a value then why is const auto& j = 42; ok?
 
Is the rule that auto can't refer to a value but const auto can?
 
Paul
 
auto &g = ci; // g is a const int& that is bound to ci
auto &h = 42; // error: we can't bind a plain reference to a value
const auto &j = 42; // ok:
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: