Tuesday, June 16, 2015

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

Doug Mika <dougmmika@gmail.com>: Jun 16 02:13PM -0700

Why can't I do the following:
#include <iostream>
#include <string>
 
using namespace std;
 
template<typename T>
struct C {
using value_type=T;
string name;
int number;
};
 
int main()
{
C<int> c1{"Michael", 1};
C<string> c2{"Suzanne",2};

c1.value_type x; //Line xx - doesn't work
 
return 0;
}
 
Instead what I must do in line xx is decltype(c1)::value_type x;?
Is value_type a member of c1? (just as is name)
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 16 05:23PM -0400

On 6/16/2015 5:13 PM, Doug Mika wrote:
> }
 
> Instead what I must do in line xx is decltype(c1)::value_type x;?
> Is value_type a member of c1? (just as is name)
 
It's a member of the class, not a member of an object.
 
V
--
I do not respond to top-posted replies, please don't ask
Doug Mika <dougmmika@gmail.com>: Jun 16 02:45PM -0700

On Tuesday, June 16, 2015 at 4:23:18 PM UTC-5, Victor Bazarov wrote:
 
> V
> --
> I do not respond to top-posted replies, please don't ask
In that case wondering whether you'd know:
 
on the reference site, query vector:
http://www.cplusplus.com/reference/vector/vector/?kw=vector
 
when you scroll down it gives a list of Member Types. How can I know whether they are object members or class members?
Paavo Helde <myfirstname@osa.pri.ee>: Jun 16 04:55PM -0500

Victor Bazarov <v.bazarov@comcast.invalid> wrote in news:mlq41d$2n3$2
 
>> Instead what I must do in line xx is decltype(c1)::value_type x;?
>> Is value_type a member of c1? (just as is name)
 
> It's a member of the class, not a member of an object.
 
Static member functions are also members of the class, yet can be called
on an object. Just saying...
 
Cheers
Paavo
legalize+jeeves@mail.xmission.com (Richard): Jun 16 02:59PM -0600

[Please do not mail me a copy of your followup]
 
slp53@pacbell.net spake the secret code
 
>Granted most of that code ran sans OS (it was the OS), and required
>fixed types to map to various hardware registers.
 
This is the situation where I think the size of the data really *does*
matter and it's important to use sized types and not the implicit size
of int, long, etc. Things like structures representing byte streams
passed across the network (and you might do network-to-host byte
reordering in place on that structure), raw byte streams read from or
written to files, raw bytes transmitted between processes through
shared memory segments and so-on.
 
I've got some code im my open source project that doesn't use
specifically sized types for some binary file I/O and it's a mess right
because they used generic types. So I am certainly sympathetic to
cases where it matters.
 
My assertion is that it simply doesn't matter in *every* case.
 
>run into many issues in the past porting software from 16-bit
>ints to 32-bit ints (and from 32-bit longs to 64-bit longs),
>I would never advocating using 'int' for anything.
 
Here, I disagree. The size of every int in a program isn't a
portability concern. What's important is deciding which variables need
specific sizes and which don't.[*]
 
I've seen code where the compiler's default size of an int was 16-bits
and everywhere they wanted to iterate over containers or whatnot it was
int16_t all over the place. Then you move to a compiler where the
defaault size of an int is 32-bits. The fact that all those ints were
marked as 16-bits is now erroneous and simply a distraction. How do
you know which ones really needed to be 16-bits and which were 16-bits
simply because that was the default size of an int? Forcing them all
into a 16-bit straight jacket impedes portability instead of enhancing
it.
 
In other words, like most things in programming, it's a matter of good
judgment. Simplistically applying a rule like "never use int" is
opening up your skull and dumping your brains in the garbage. There is
a time when specifically sized types are important.
 
For most of the C++ I have worked on in the past 25 years, it was
important in only a very few cases. Working on code where the team
insisted on sizing every single named quantity in the application was
tedious and yielded little to no value. I have done very little
programming in embedded environments with strict resource limits and I
can see how someone who spent 25 years in that environment would
consider it indispensible that everything be specifically sized. So it
varies with experience and problem domain.
 
But this is just another reason to advocate for proper application of
good judgment for your problem domain instead of adopting a simplistic
rule. Even within a problem domain, things can change over time.
Embedded processors today have access to many more resources than they
did in the 80s when 64 users time shared out of 128KB of main memory
and an embedded CPU was lucky to have 128 bytes of RAM and 16K of ROM.
 
[*] Aside: if sizing is all that important, does that mean you encode
the byte size of a struct into its name? I mean, if it's really that
important for int to be declared to be a specific size, but you don't
similarly mandate the same thing for structs and classes, then this
is an academic exercise in pedantry.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
 
 
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
James Kuyper <jameskuyper@verizon.net>: Jun 16 02:59PM -0600

On 06/16/2015 09:05 AM, David Brown wrote:
...
 
> MISRA standards are only £10 or £15 for the pdfs - it's not /that/
> expensive! (But of course any cost makes the whole process a lot more
> inconvenient, especially if you just want a quick look for curiosity.)
 
IIRC, the last time I looked it was several hundred US$. A year ago, I
would have thought that £10 it would be almost worth paying for, just
out of curiosity. However, since the twins arrived I'm paying closer
attention to my money.
 
 
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
"Chris M. Thomasson" <nospam@nospam.nospam>: Jun 16 03:03PM -0600

> concerned the MISRA C++ coding standard for safey critical systems
> prohibits the use of basic numerical types and mandates the use of the
> typedefs from <cstdint> (or an equivalent).
 
Programming a warplane, anyone?:
 
http://www.stroustrup.com/JSF-AV-rules.pdf
 
;^)
 
 
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 16 04:47PM -0600

On 16/06/2015 21:59, Richard wrote:
> simply because that was the default size of an int? Forcing them all
> into a 16-bit straight jacket impedes portability instead of enhancing
> it.
 
This is why you should design things properly perhaps by the use of a
traits class specialized for different hardware which has its own public
typedefs:
 
template <typename HardwareType>
struct foo_traits;
 
template <>
struct foo_traits<ZXSpectrum48K>
{
typedef uint16_t index_type;
};
 
typedef foo_traits<ZXSpectrum48K>::index_type index_type;
 
/* use index_type rather than uint16_t directly. */
 
/Flibble
 
 
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
David Brown <david.brown@hesbynett.no>: Jun 16 04:47PM -0600

On 16/06/15 22:59, James Kuyper wrote:
> would have thought that £10 it would be almost worth paying for, just
> out of curiosity. However, since the twins arrived I'm paying closer
> attention to my money.
 
That must have been a /long/ time ago - or perhaps you are mixing it
with some other standards (such as the current C++ standard, which is an
absurd $265).
 
If you have anything specific you want to ask about MISRA, let me know
and I can look it up - I can't send you a copy (since it would be
copyright infringement, and the pdf is watermarked with my name).
 
 
 
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 16 04:47PM -0600

On 16/06/2015 22:03, Chris M. Thomasson wrote:
>> typedefs from <cstdint> (or an equivalent).
 
> Programming a warplane, anyone?:
 
> http://www.stroustrup.com/JSF-AV-rules.pdf
 
From that document (relevant to this thread):
 
AV Rule 209 (MISRA Rule 13, Revised)
The basic types of int, short, long, float and double *shall not* be
used, but specific-length
equivalents should be typedef'd accordingly for each compiler, and these
type names used in
the code.
Rationale: Since the storage length of types can vary from compiler to
compiler and
platform-to-platform, this rule ensures that code can be easily
reconfigured for storage size
differences by simply changing definitions in one file. See AV Rule 209
in Appendix A for
additional details.
Exception: Basic types are permitted in low-level routines to assist in
the management of
word alignment issues (e.g. memory allocators).
MISRA rule was changed from should to shall.
 
/Flibble
 
 
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Doug Mika <dougmmika@gmail.com>: Jun 16 01:52PM -0700

On Tuesday, June 16, 2015 at 1:03:41 PM UTC-5, Richard wrote:
> The Computer Graphics Museum <http://computergraphicsmuseum.org>
> The Terminals Wiki <http://terminals.classiccmp.org>
> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
 
My first question was indeed, what is ->, that's clear now.
But the question that remains is why would we overload the + operator on a class C, for example, outside of the class? Why not include operator+ inside our class C definition?
legalize+jeeves@mail.xmission.com (Richard): Jun 16 09:11PM

[Please do not mail me a copy of your followup]
 
Doug Mika <dougmmika@gmail.com> spake the secret code
>But the question that remains is why would we overload the + operator on
>a class C, for example, outside of the class? Why not include operator+
>inside our class C definition?
 
Prefer small, simple classes over large ones.
 
If you force everything to be a member function, even those functions
that aren't *required* to be a member function, then you end up with
the rather large bloated class that is std::string. The rule of thumb
is: if you can implement something as a free function (i.e. not a
member function) using the public interface of a class then prefer that
over a member function.
 
This goes hand-in-hand with the advice for namespaces -- the only thing
not in a namespace is your implementation of main(). You put the class
and its associated free functions all inside a namespace and then they
don't get in the way of other free functions for other classes and ADL
guarantees that the right operator+ is selected when used with that
class.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 16 05:13PM -0400

On 6/16/2015 4:52 PM, Doug Mika wrote:
> [..] the question that remains is why would we overload the +
> operator on a
class C, for example, outside of the class? Why not include operator+
inside our class C definition?
 
It's a design choice. Two-operand operators are often defined outside
of the class to allow conversions to take place on either operand, not
just the right-hand one.
 
V
--
I do not respond to top-posted replies, please don't ask
Doug Mika <dougmmika@gmail.com>: Jun 16 02:17PM -0700

On Tuesday, June 16, 2015 at 4:13:35 PM UTC-5, Victor Bazarov wrote:
 
> V
> --
> I do not respond to top-posted replies, please don't ask
 
What sort of conversions are we speaking of?
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 16 05:22PM -0400

On 6/16/2015 5:17 PM, Doug Mika wrote:
>> --
>> I do not respond to top-posted replies, please don't ask
 
> What sort of conversions are we speaking of?
 
<sigh>
 
What book are you reading that doesn't explain conversions?
 
struct ConvertibleFromInt {
ConvertibleFromInt(int) {}
};
 
...
ConvertibleFromInt c = 42;
 
Now compare
 
struct PlusAsMember {
PlusAsMember(int) {}
PlusAsMember operator+(PlusAsMember const& rhs) const;
};
...
PlusAsMember p(42);
 
p + 777; // OK
777 + p; // NOT OK
 
with this
 
struct PlusOutside {
PlusOutside(int) {}
};
 
PlusOutside operator+(PlusOutside const& o1,
PlusOutside const& o2);
 
...
PlusOutside p(42);
 
p + 777; // OK
777 + p; // OK
 
In order to try those things, add code to make them complete programs,
then compile.
 
V
--
I do not respond to top-posted replies, please don't ask
Martin Shobe <martin.shobe@yahoo.com>: Jun 16 02:50PM -0500

On 6/16/2015 2:14 PM, Victor Bazarov wrote:
 
> Allocation of a plain int is often expensive in both memory and time,
> and besides, who owns that pointer and who's going to deallocate that
> memory when it's not needed anymore?
 
Depends on your design, but the typical case is the caller.
 
> What if a C API call happens
> periodically with the same value, do you propose to allocate it every
> time and deallocate after the call has returned?
 
Depends on your design, but the typical case is no.
 
> What if API is such
> that it needs to retain the value for a few calls?
 
Then it does so.
 
> A literal would be
> much less trouble than managing the lifetime of a single 'int'.
 
much less? I think I detect a bit of hyperbole.
 
> Not saying that such a solution is unacceptable, just that it's not
> necessarily easy or as clean as it might appear at a first glance.
 
It's not as hard as you are making it out to be. Presumably, the
original poster is doing something like this.
 
void bar()
{
int x = 42;
 
....
// foo will call f with x.
foo(f, (void *) x);
...
}
 
void f(void * p)
{
int i = (int) p;
...
}
 
The suggested change is to do this instead
 
void bar()
{
int x = 42;
 
...
// foo will call f with x.
foo(f, &x);
...
}
 
void f(void * p)
{
int i = *((int *) p);
...
}
 
Martin Shobe
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 16 03:55PM -0400

On 6/16/2015 3:50 PM, Martin Shobe wrote:
 
>> What if API is such
>> that it needs to retain the value for a few calls?
 
> Then it does so.
 
OK. Now consider this. It does so, and it gets called from other
functions of the same API some time later, and the local variable has
gone out of scope and its address contains garbage...
 
It's an unlikely scenario, yet not completely unheard of, that the API
has a state that it wants to maintain.
 
 
>> A literal would be
>> much less trouble than managing the lifetime of a single 'int'.
 
> much less? I think I detect a bit of hyperbole.
 
Not if the lifetime has to be managed across modules or beyond one API call.
 
> int i = *((int *) p);
> ...
> }
 
Bad idea using C-style casts, that one of the points I failed to
deliver, I am guessing...
 
V
--
I do not respond to top-posted replies, please don't ask
David Brown <david.brown@hesbynett.no>: Jun 16 10:20PM +0200

On 16/06/15 21:50, Martin Shobe wrote:
> ...
> }
 
> Martin Shobe
 
That's fine as long as x is still alive before f gets called. But often
these sorts of things are for registering some sort of callback - foo
won't actually call f directly, but arrange for it to be called later.
Thus you have to make sure x is still alive after bar has exited - and
that means dynamic memory and a lot of pain.
 
A far better arrangement is to use a union instead of a void*, so that
you can pass either small value data (such as an int or two) or a
pointer to larger data.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 16 09:37PM +0100

On Tue, 16 Jun 2015 20:16:11 +0200
 
> Too ,bad ;(
> I need intptr_t as conversion is actually passing int parameter as
> void* and than back to int.

This is a common idiom in C libraries, and if you are doing the
conversions that way, and all your numerical manipulation is done using
ints, you don't need to worry about whether the size of void* is larger
than the size of int. If you begin with a value in the range of int you
will end with a value within the range of int and the conversion will
work. (You do have to worry if the size of int is larger than the size
of void*, but I know of no implementation where that is the case.)
 
Chris
legalize+jeeves@mail.xmission.com (Richard): Jun 16 09:07PM

[Please do not mail me a copy of your followup]
 
Victor Bazarov <v.bazarov@comcast.invalid> spake the secret code
>> any void* to a pointer of type T (although the result is undefined
>> behavior of the void* didn't come from a pointer to type T).
 
>Allocation of a plain int is often expensive in both memory and time,
 
Code for simplicity, readability and understanding first and get all
obsessive about allocating a single int later only if it actually
matters. (I'm really hard-pressed to think of a single case where
allocating a single int is really going to matter.)
 
>and besides, who owns that pointer and who's going to deallocate that
>memory when it's not needed anymore?
 
All these C-style APIs that use void* context pointers have ways of
managing the lifetime of the memory. Remember, they already have to
solve that problem for C; it is no different for C++.
 
>What if a C API call happens
>periodically with the same value, do you propose to allocate it every
>time and deallocate after the call has returned?
 
The original poster didn't specify this, but in general, this is NOT
how C style callback APIs work when they use a void* context pointer.
I've used plenty of them (the X11 Toolkit, Xt, is riddled with them).
 
>Not saying that such a solution is unacceptable, just that it's not
>necessarily easy or as clean as it might appear at a first glance.
 
While these concerns aren't unreasonable for some unspecified API, it
is not typically how C style APIs with callbacks work. If they are
doing any of the things you raise, then their API is simply broken both
for C and C++.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Melzzzzz <mel@zzzzz.com>: Jun 16 11:07PM +0200

On Tue, 16 Jun 2015 22:20:23 +0200
> - foo won't actually call f directly, but arrange for it to be called
> later. Thus you have to make sure x is still alive after bar has
> exited - and that means dynamic memory and a lot of pain.
 
That is the case.
 
 
> A far better arrangement is to use a union instead of a void*, so
> that you can pass either small value data (such as an int or two) or
> a pointer to larger data.
 
Can't change framework.
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 16 05:17PM -0400

On 6/16/2015 5:07 PM, Richard wrote:
> [..]
> The original poster didn't specify this, but in general, this is NOT
> how C style callback APIs work when they use a void* context pointer.
 
"All generalizations are wrong". Think about it.
 
> I've used plenty of them (the X11 Toolkit, Xt, is riddled with them).
> [..]
 
V
--
I do not respond to top-posted replies, please don't ask
Noob <root@127.0.0.1>: Jun 16 10:16PM +0200

On 16/06/2015 21:04, Richard wrote:
 
> to the allocator for reuse. All memory obtained from the operating
> system (in modern operating systems, anyway) is zeroed before being
> given to the allocator in the C++ runtime.
 
I refined the test program.
 
#include <cstring>
#include <cstdio>
 
class foo {
public:
int i = 42;
int v[5] = { 1, 2, 3 };
int uninit[100];
};
 
#define SIZE (1<<16)
 
static void dump(foo *p)
{
printf("%d %d %d %x\n", p->i, p->v[2], p->v[4], p->uninit[12]);
}
 
int main(void)
{
char *mem = new char[SIZE]; std::memset(mem, 0x1, SIZE); delete[] mem;
foo xxa;
foo xxb{};
foo *xxc = new foo;
foo *xxd = new foo();
foo *xxe = new foo{};
foo *xxf = new foo[20]{};
foo *xxg = new foo[20];
dump(&xxa); dump(&xxb); dump(xxc); dump(xxd); dump(xxe); dump(xxf+3); dump(xxg+7);
return 0;
}
 
$ g++ -std=c++11 -Wall -Wextra -ggdb3 init.cpp
$ ./a.out
42 3 0 f76bbc10
42 3 0 0
42 3 0 1010101
42 3 0 0
42 3 0 0
42 3 0 0
42 3 0 1010101
 
So the syntax for xxa, xxc, xxg leaves "uninit" uninitialized, while the
syntax for xxb, xxd, xxe, xxf 0-initializes "uninit".
 
So if I had a proper C++11 compiler, I could just delete
the existing constructors, and change the object definitions
to the new foo[N]{}; syntax.
 
What version of Visual C++ fully supports C++11?
What version of gcc fully supports C++11?
 
Regards.
Noob <root@127.0.0.1>: Jun 16 10:29PM +0200

On 16/06/2015 22:16, Noob wrote:
 
> What version of Visual C++ fully supports C++11?
 
Looking bleak.
http://blogs.msdn.com/b/vcblog/archive/2014/11/17/10573602.aspx
https://blogs.msdn.com/b/vcblog/archive/2014/08/19/the-future-of-non-static-data-member-initialization.aspx
 
[1] NSDMIs and initializer lists were previously listed as Yes, but have been downgraded to Partial. After users encountered silent bad codegen when using braced-init-lists in NSDMIs and mem-initializer-lists, the compiler team blocked these broken scenarios with a compiler error C2797. This VCBlog post published in August has more info, and this is planned to be completely fixed in 2015 RTM.
 
> What version of gcc fully supports C++11?
 
https://gcc.gnu.org/projects/cxx0x.html
Non-static data member initializers supported since gcc 4.7
 
Regards.
legalize+jeeves@mail.xmission.com (Richard): Jun 16 09:02PM

[Please do not mail me a copy of your followup]
 
Victor Bazarov <v.bazarov@comcast.invalid> spake the secret code
>> What is the difference between new foo; and new foo{}; ?
 
>'new foo' default-initializes the object, 'new foo{}' performs the so
>called direct-initialization. They differ a bit.
 
I think they only differ when you actually supply values and not when
the list is empty when we're talking about classes.
 
I'm going from 8.5 Initializers in the standard, which says this about
direct initialization:
 
"The initialization that occurs in the forms
 
T x(a);
T x{a};
 
as well as in new expressions (5.3.4), static_cast expressions
(5.2.9), functional notation type conversions (5.2.3), and base
member initializers (12.6.2) is called direct-initialization."
 
I interpret this to mean that the 'a' argument is important here.
 
Earlier it is stated that X a() is value initialization.
 
>The one without the
>braces looks for a c-tor that can be called without the arguments, and
>if found, calls it. If none exist, it leaves the object uninitialized!
 
Not quite. 8.5 paragraph 12 says
 
"If no initializer is specified for an object, the object is
default-initialized."
 
Default initialization is specified as:
 
"To default-initialize an object of type T means:
- if T is a class type, the default constructor for T is called (and
the initialization is ill-formed if T has no default constructor or
overload resolution results in an ambiguity or in a function that is
deleted or is inaccessible from the context of the initialization);
- if T is an array type, each element is default-initialized;
- otherwise, no initialization is performed."
 
I interpret this to mean that the program is ill-formed if the default
constructor is unavailable for whatever reason. Generally, ill-formed
to a compiler means an error.
 
So when is the "no initialization performed"? If T is anything other
than a class, i.e. a scalar type such as int, pointer, double, float,
etc.
 
Do you interpret this differently? I am not claiming expertise in the
standard, simply interpreting it as I read it.
 
>IOW, 'new foo' ignores the individuals member initializers while 'new
>foo{}' uses those.
 
I don't think this is quite right about 'new foo' as per above.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
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: