Thursday, April 30, 2020

Digest for comp.lang.c++@googlegroups.com - 19 updates in 3 topics

Juha Nieminen <nospam@thanks.invalid>: Apr 30 06:19AM

> (IMHO both C and C++ should have made internal linkage the default for
> all data and functions from the start, and required an explicit "extern"
> for external linkage, but it's far too late to fix that!)
 
I think that there's a slight problem with that in that if you define a
const variable in a header file, if it has internal linkage by default,
it will be duplicated in every compilation unit where it's used (unless
the compiler can "inline" it).
 
This *is* actually a slight problem in C++, IMO. It's easy to put
something like
 
namespace MySpace
{
const std::vector<int> values = { 1, 2, 3, 4 };
}
 
in a header file without realizing that the vector will be duplicated in
all compilation units where it's used, and thus duplicated that many times
in the executable binary (unless the compiler somehow optimizes this).
 
Of course nowadays we can declare it as 'inline' which solves the problem,
but that has to be explicitly specified, and it needs compiler support.
Melzzzzz <Melzzzzz@zzzzz.com>: Apr 30 06:57AM

> in the executable binary (unless the compiler somehow optimizes this).
 
> Of course nowadays we can declare it as 'inline' which solves the problem,
> but that has to be explicitly specified, and it needs compiler support.
 
What's difference if `inline`?
 
 
--
current job title: senior software engineer
skills: c++,c,rust,go,nim,haskell...
 
press any key to continue or any other to quit...
U ničemu ja ne uživam kao u svom statusu INVALIDA -- Zli Zec
Svi smo svedoci - oko 3 godine intenzivne propagande je dovoljno da jedan narod poludi -- Zli Zec
Na divljem zapadu i nije bilo tako puno nasilja, upravo zato jer su svi
bili naoruzani. -- Mladen Gogala
David Brown <david.brown@hesbynett.no>: Apr 30 09:20AM +0200

On 30/04/2020 08:19, Juha Nieminen wrote:
> const variable in a header file, if it has internal linkage by default,
> it will be duplicated in every compilation unit where it's used (unless
> the compiler can "inline" it).
 
You put const definitions in a header if you are happy to have them
duplicated - if not, you put the definition and initialisation in a
single file and make the "const" external. The C++ "default to static"
rule for const is so that you can easily use "const int noOfThings = 4;"
instead of C-style "#define noOfThings 4". The expectation is that the
const objects defined in a header have less than zero cost - they don't
take up space, they don't require run-time initialisation, and they get
folded into code just like a literal constant.
 
If you are putting large "const" data in headers, then surely you /know/
that this will may take duplicate space?
 
It can still be a useful thing that people want to do - hence the trick
of using static members in a template, and then the much nicer step of
adding inline variables to the language.
 
 
> in a header file without realizing that the vector will be duplicated in
> all compilation units where it's used, and thus duplicated that many times
> in the executable binary (unless the compiler somehow optimizes this).
 
Do people do this sort of thing without realising the consequences?
 
Jorgen Grahn <grahn+nntp@snipabacken.se>: Apr 30 07:58AM

On Thu, 2020-04-30, David Brown wrote:
> On 30/04/2020 08:19, Juha Nieminen wrote:
...
 
>> all compilation units where it's used, and thus duplicated that many times
>> in the executable binary (unless the compiler somehow optimizes this).
 
> Do people do this sort of thing without realising the consequences?
 
Looks like something I might easily do. I'm weak in this area (but
not weaker than my coworkers, I think).
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
David Brown <david.brown@hesbynett.no>: Apr 30 01:01PM +0200

On 30/04/2020 09:58, Jorgen Grahn wrote:
 
>> Do people do this sort of thing without realising the consequences?
 
> Looks like something I might easily do. I'm weak in this area (but
> not weaker than my coworkers, I think).
 
Perhaps it is just that for my type of work, I think about such
efficiencies all the time - and thus don't make that kind of mistake.
(I make other mistakes instead :-) )
Tim Rentsch <tr.17687@z991.linuxsc.com>: Apr 30 04:49AM -0700


> One curious difference between C and C++, which I only learned the
> details of recently, is the difference in semantics of a const
> variable at the global scope. [elaboration]
 
Right. I did actually think of this one, but it didn't
pop up in my test compiles so I forgot to include it.
Tim Rentsch <tr.17687@z991.linuxsc.com>: Apr 30 04:59AM -0700


> Since C libraries often use more than just function declarations,
> C++ still needs to support eg. C style structs, typedefs, etc.
> Breaking compatibility with C libraries would be a huge setback.
 
What I would like to see is for C++ to define how extern "C" blocks
work so that inside extern "C" { ... } what is accepted is C syntax,
and for that part of the source uses C semantics. If this were
done it is then trivial to write C headers that C++ can #include,
and guaranteed that what they do in C++ is the same as what they do
in C. Since it is C++ that wants to include C headers, and not the
other way around, it is C++ that should more of the heavy lifting
needed to get that to happen.
Tim Rentsch <tr.17687@z991.linuxsc.com>: Apr 30 05:08AM -0700


> Since C libraries often use more than just function declarations,
> C++ still needs to support eg. C style structs, typedefs, etc.
> Breaking compatibility with C libraries would be a huge setback.
 
Postscript: I wouldn't mind adding a construct in C so that
 
extern "C" {
...
}
 
were accepted as C source, with the same effect as leaving off
the enclosing tokens. Surely it is almost no effort to add such
a rule to the language, and it would make writing C++-compatible
headers even easier. This idea, coupled with the suggestion
given in my other posting, is all that is needed to "harmonize"
C and C++ as far as headers are concerned.
Jorgen Grahn <grahn+nntp@snipabacken.se>: Apr 30 07:53PM

On Thu, 2020-04-30, David Brown wrote:
>> not weaker than my coworkers, I think).
 
> Perhaps it is just that for my type of work, I think about such
> efficiencies all the time - and thus don't make that kind of mistake.
 
That's surely part of it: I work with large and old programs where the
worst inefficiencies are in the I/O, and the other inefficiencies are
lost in the background noise.
 
(Although in a recent hobby project, I kicked out std::regex when I noticed
it doubled the code segment size.)
 
> (I make other mistakes instead :-) )
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Apr 30 02:18PM -0700

Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
[...]
> in C. Since it is C++ that wants to include C headers, and not the
> other way around, it is C++ that should more of the heavy lifting
> needed to get that to happen.
 
Interesting idea, but I'm not convinced that requiring C++ compilers to
handle
extern "C" {
int *class = malloc(sizeof 'A');
}
would be worth the implementation effort.
 
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */
James Kuyper <jameskuyper@alumni.caltech.edu>: Apr 30 07:19PM -0400

Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
[...]
> in C. Since it is C++ that wants to include C headers, and not the
> other way around, it is C++ that should more of the heavy lifting
> needed to get that to happen.
 
Interesting - that would turn a popular misconception into reality,
which might qualify as an argument in favor of the idea.
 
However, code inside an extern "C" {} block has had C++ semantics for at
least as long as those semantics have been different from C semantics
(early versions of C++ were simply "C with classes" - the semantics
weren't very different at that time). As a result, a fair amount of code
has been written that either accidentally or intentionally depends upon
that fact. As a result, such a change would probably break a fair amount
of existing code.
 
There's another closely related problem. I get the impression that
you're thinking primarily in terms of using extern "C" function
declarations in C++ code to give that C++ code the ability to call
functions implemented in C. However, you're also allowed to provide
extern "C" definitions for C++ functions that are callable from C. I'm
assuming, in particular, that "C semantics" would prohibit calling
functions declared with other language linkages. If that's not the case,
you need to more precisely specify what you mean by "C semantics".
 
If the C++ standard were modified as you describe, how could such code
be re-written?
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo>: Apr 29 10:47PM -0400

Vir Campestris wrote:
 
> (I'd be happier if the parameter was a Collection<Object> for better type safety)
 
> Any ideas?
 
> Andy
 
This seems to work for me:
 
#include <iostream>
#include <vector>
#include <list>
 
using namespace std;
 
struct Object {
};
 
ostream&
operator<<(ostream &os, const Object &o)
{
return os << "Object " << (void*)&o;
}
 
vector<Object> vec{Object(), Object()};;
list<Object> lst{Object(), Object(), Object()};
 
template <typename Collection, typename T = typename Collection::value_type>
ostream&
operator<<(
ostream& o,
const Collection& objects) {
for (const T & e: objects)
o << e << '\t';
return o;
}
 
int
main(int, char*[])
{
cout << vec << ' ' << lst << endl;
return 0;
}
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 30 06:39AM +0200

On 30.04.2020 04:47, Pavel wrote:
> cout << vec << ' ' << lst << endl;
> return 0;
> }
 
Detecting that a type is a collection type, without false positives, is
difficult. Consider that e.g. `std::is_same` is an
`std::integral_constant<bool, V>` with V either `true` or `false`. This
is a type with a `value_type`, and implicit conversion to `bool`:
 
 
----------------------------------------------------------------
#include <iostream>
#include <type_traits>
using namespace std;
 
auto main()
-> int
{
cout << boolalpha;
cout << is_same<short, short>() << endl; // "true"
cout << is_same<short, long>() << endl; // "false"
}
----------------------------------------------------------------
 
 
But with your `operator<<` template in the picture it will be selected
to output those `std::integral_constant` instances, and treating those
instances as collections will just fail to compile.
 
So, instead, check for the features that are actually used.
 
The following appears to work for standard library collections:
 
 
template <typename Collection, typename T = typename
Collection::const_iterator>
ostream&
operator<<(
ostream& o,
const Collection& objects) {
for (const auto& e: objects)
o << e << '\t';
return o;
}
 
 
However, for a more general solution I think I would define a general
thin wrapper type à la `std::reference_wrapper` to use as argument, and
let the client code explicitly specify (via use of that wrapper type)
that it wants to invoke the for-collections overload of `<<`.
 
Simply, explicit = good, implicit = not so good, in general.
 
 
- Alf
Juha Nieminen <nospam@thanks.invalid>: Apr 30 06:24AM

> Detecting that a type is a collection type, without false positives, is
> difficult.
 
Would C++20 concepts help here?
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 30 01:10PM +0200

On 30.04.2020 08:24, Juha Nieminen wrote:
>> Detecting that a type is a collection type, without false positives, is
>> difficult.
 
> Would C++20 concepts help here?
 
I hope so. But I don't know. Sorry.
 
- Alf
Vir Campestris <vir.campestris@invalid.invalid>: Apr 30 09:26PM +0100

On 30/04/2020 05:39, Alf P. Steinbach wrote:
> thin wrapper type à la `std::reference_wrapper` to use as argument, and
> let the client code explicitly specify (via use of that wrapper type)
> that it wants to invoke the for-collections overload of `<<`.
 
It's a little hacky project I'm doing purely for my own amusement. It
doesn't need to be clean really :)
 
But thank you both. It was annoying me!
 
Andy
Ralf Goertz <me@myprovider.invalid>: Apr 30 03:46PM +0200

Hi,
 
I just noticed that std::filesystem::copy_options::overwrite_existing
doesn't have an effect using gcc 9.3.0 under windows but works fine
under linux. That is, the program
 
#include <filesystem>
 
int main() {
std::filesystem::copy_file("foo","bar",std::filesystem::copy_options::overwrite_existing);
}
 
throws with
 
terminate called after throwing an instance of 'std::filesystem::__cxx11::filesystem_error'
what(): filesystem error: cannot copy file: File exists [foo] [bar]
 
provided that the regular files "foo" and "bar" exist. Under linux this
only happens if I omit the copy option. Since this is such a trivial
thing and I don't find any reports on gcc's bugzilla I wonder if this
behaviour is standard conforming. But then there is also nothing on
cpprefererence.com on that (AFAICT). Can this really be a bug?
James Kuyper <jameskuyper@alumni.caltech.edu>: Apr 30 10:37AM -0400

On 4/30/20 9:46 AM, Ralf Goertz wrote:
> thing and I don't find any reports on gcc's bugzilla I wonder if this
> behaviour is standard conforming. But then there is also nothing on
> cpprefererence.com on that (AFAICT). Can this really be a bug?
 
The standard only allows an implementation to "Report a file already
exists error as specified in 30.10.7 if:
(4.1.1) — !is_regular_file(from), or
(4.1.2) — exists(to) and !is_regular_file(to), or
(4.1.3) — exists(to) and equivalent(from, to), or
(4.1.4) — exists(to) and
(options & (copy_options::skip_existing |
copy_options::overwrite_existing |
copy_options::update_existing)) == copy_options::none"
 
Do any of those possibilities apply? If not, it's a bug.
Paavo Helde <eesnimi@osa.pri.ee>: Apr 30 10:58PM +0300

30.04.2020 16:46 Ralf Goertz kirjutas:
> thing and I don't find any reports on gcc's bugzilla I wonder if this
> behaviour is standard conforming. But then there is also nothing on
> cpprefererence.com on that (AFAICT). Can this really be a bug?
 
FWIW, compiling this program with my Cygwin gcc 9.3.0 in Windows works
as expected (copies the file).
 
Note that in Windows the files may be easily locked by other programs
(including non-obvious ones like virus scanners) so that they cannot be
deleted (though in this case the error message should probably be
something like "Access denied").
 
In Unix world file deletion means just a refcount drop in inode which
has a much better chance to succeed. To cope with that deficiency there
is even a special Windows feature (MoveEx) to schedule files for
deletion on next restart.
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: