Friday, October 12, 2018

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

Lynn McGuire <lynnmcguire5@gmail.com>: Oct 12 01:33PM -0500

"Rust vs. C++ Comparison"

https://www.codeproject.com/Articles/1263195/Rust-vs-Cplusplus-Comparison
 
Very informative. Interesting but not gonna happen.
 
Lynn
"Öö Tiib" <ootiib@hot.ee>: Oct 12 12:38PM -0700

On Friday, 12 October 2018 21:33:53 UTC+3, Lynn McGuire wrote:
> "Rust vs. C++ Comparison"
 
> https://www.codeproject.com/Articles/1263195/Rust-vs-Cplusplus-Comparison
 
> Very informative. Interesting but not gonna happen.
 
What is not going to happen? Rust works and about as efficiently as C++
and C. It is indeed bit annoying to program in Rust. But some like
those inconveniences.
 
Efficiency advantage of C, C++ and Rust actually exists only in very
good hands. Several other languages like Haskell, Lisp, FORTRAN,
JavaScript and proprietary languages of Oracle, Microsoft, Google
and Apple are close enough. There are no real point to translate
between those languages because of efficiency.
 
Therefore Rust plays a quite attractive card of compile time protection
against buffer overflows, nulls and race conditions that C and C++
don't have. ;)
Melzzzzz <Melzzzzz@zzzzz.com>: Oct 12 09:25PM


> What is not going to happen? Rust works and about as efficiently as C++
> and C. It is indeed bit annoying to program in Rust. But some like
> those inconveniences.
 
Rust is not an OO language. Also it does not have pointer arithmetic,
so if you want it you have to cast to integer then add, then convert
back to pointer.
traits in Rust are mainly used as constraints for generic functions.
You can't implement doubly linked list with safe code and almost
anythingi at that.
Language is not stable at all. What you compile by stable version
won't compile with nightly and vice versa.
But it is good in a sense that it borrowed from functional languages.
Also, macros are better.
after moving object, destructor won't be called
of moved object. And lot of other things are nice.
here are my two repos one is trees other is scimark2 in Rust:
https://github.com/bmaxa/trees_rust
https://github.com/bmaxa/scimark2rust
You can't see that indeed that you can program unsafely in Rust ;)
 
 
--
press any key to continue or any other to quit...
Paul <pepstein5@gmail.com>: Oct 12 12:09PM -0700

The code below is from Hackerrank. It looks suspicious to me because
the memory is allocated with new but freed with free.
 
Is it ok?
 
Thanks,
 
Paul
 
 
using namespace std;
 
class SinglyLinkedListNode {
public:
int data;
SinglyLinkedListNode *next;
 
SinglyLinkedListNode(int node_data) {
this->data = node_data;
this->next = nullptr;
}
};
 
class SinglyLinkedList {
public:
SinglyLinkedListNode *head;
SinglyLinkedListNode *tail;
 
SinglyLinkedList() {
this->head = nullptr;
this->tail = nullptr;
}
 
void insert_node(int node_data) {
SinglyLinkedListNode* node = new SinglyLinkedListNode(node_data);
 
if (!this->head) {
this->head = node;
} else {
this->tail->next = node;
}
 
this->tail = node;
}
};
 
 
void free_singly_linked_list(SinglyLinkedListNode* node) {
while (node) {
SinglyLinkedListNode* temp = node;
node = node->next;
 
free(temp);
}
}
"Öö Tiib" <ootiib@hot.ee>: Oct 12 01:11PM -0700

On Friday, 12 October 2018 22:09:22 UTC+3, Paul wrote:
> The code below is from Hackerrank. It looks suspicious to me because
> the memory is allocated with new but freed with free.
 
> Is it ok?
 
Calling free on pointers that aren't null and weren't returned from
aligned_alloc, calloc, malloc or realloc is undefined behavior AFAIK.
Also free may not call delete (like those others may not call new).
However users can guarantee that new returns the pointers from one of
those functions by globally overloading new.
Ian Collins <ian-news@hotmail.com>: Oct 13 09:20AM +1300

On 13/10/18 08:09, Paul wrote:
> The code below is from Hackerrank. It looks suspicious to me because
> the memory is allocated with new but freed with free.
 
> Is it ok?
 
No!
 
The pointer returned by new may not have been allocated with malloc, so
passing it to free is undefined behaviour. Also calling free will not
invoke an object's destructor.
 
--
Ian.
Jorgen Grahn <grahn+nntp@snipabacken.se>: Oct 12 08:26AM

On Thu, 2018-10-11, Thiago Adams wrote:
 
> Is it guarantee to initialize 'i' with '0'?
 
> I tried to find the answer in but it is not clear.
 
> https://en.cppreference.com/w/cpp/language/default_initialization
 
I recently had to find out, and I can report that "The C++ Programming
Language" explains it well.
 
But if you have to know, I think you're either working with C structs,
or (my case) trying to understand broken code. It's almost always
better to let the class itself decide what should be initialized.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Oct 12 10:59AM +0100

On Thu, 11 Oct 2018 10:21:28 -0700 (PDT)
 
> Is it guarantee to initialize 'i' with '0'?
 
> I tried to find the answer in but it is not clear.
 
> https://en.cppreference.com/w/cpp/language/default_initialization
 
Default initialization does not tell the whole story here. C++ is so
convoluted on object initialization that you are better off initializing
data members via explicit constructors.
 
Having said that, as I understand it the expression 'X *p = new X()'
performs value initialization:
https://en.cppreference.com/w/cpp/language/value_initialization
This means that, where as here X is a non-union class type without any
user-provided constructors, each non-static data member, namely 'i' is
zero initialized. (The same would not be true of the expression 'X
*p = new X': that would perform default initialization and leave 'i'
uninitialized.)
 
As I understand it, the expression 'X x = {}' performs list
initialization and, because X is an aggregate, so aggregate
initialization:
https://en.cppreference.com/w/cpp/language/aggregate_initialization
This in turn means that because no explicit value is provided for the
data member 'i', it is value initialized and so zero initialized.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Oct 12 11:32AM +0100

On Fri, 12 Oct 2018 10:59:48 +0100
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
[snip]
> zero initialized. (The same would not be true of the expression 'X
> *p = new X': that would perform default initialization and leave 'i'
> uninitialized.)
 
By the way, in C++98 'new X()' and 'new X' both did the same thing, and
only default initialize, so leaving 'i' uninitialized. This was
changed in C++03 so that 'new X()' performs value initialization.
 
You would have to be using a very old compiler to fall foul of the old
behaviour.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Oct 12 12:02PM +0100

On Thu, 11 Oct 2018 13:21:31 -0700 (PDT)
 
> > This code is printing 0 0 in release mode. (VC++ 17)
 
> > Is it guarantee to initialize 'i' with '0'?
 
> No.
 
Out of interest why do you say that zero initialization of 'i' does not
take place, via value initialization (for 'new X()') and aggregate
initialization (for 'X x = {}')?
jameskuyper@alumni.caltech.edu: Oct 12 05:44AM -0700

On Friday, October 12, 2018 at 7:02:43 AM UTC-4, Chris Vine wrote:
 
> > No.
 
> Out of interest why do you say that zero initialization of 'i' does not
> take place, via value initialization (for 'new X()') ...
 
"If the new-initializer is omitted, the object is default-initialized." (5.3.4p17).
 
"To default-initialize an object of type T means:
(7.1) — If T is a (possibly cv-qualified) class type (Clause 9), constructors are considered. The applicable constructors are enumerated (13.3.1.3), and the best one for the initializer () is chosen through overload resolution (13.3). The constructor thus selected is called, with an empty argument list, to
initialize the object." (9.3p7).
 
The citations I gave earlier indicate that a suitable constructor is implicitly declared and implicitly defined, and give the rules that apply when that constructor is called.
 
> ... and aggregate
> initialization (for 'X x = {}')?
 
I didn't think about the "X x = {};" initialization - that's my only excuse.
 
"If there are fewer initializer-clauses in the list than there are members in the aggregate, then each member not explicitly initialized shall be initialized from its default member initializer (9.2) or, if there is no default member initializer, from an empty initializer list (8.5.4)." (8.5.1p7)
 
"Otherwise, if the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized." (8.5.4p3)
 
"To value-initialize an object of type T means:
...
-- if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized and the semantic constraints for default-initialization are checked." (8.5p8)
 
So x.i == 0 is guaranteed.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Oct 12 02:22PM +0100

On Fri, 12 Oct 2018 05:44:27 -0700 (PDT)
 
> The citations I gave earlier indicate that a suitable constructor is
> implicitly declared and implicitly defined, and give the rules that
> apply when that constructor is called.
 
I don't think there is anything wrong with your earlier citations
(clearly X has an implicitly defined default constructor) but they are
incomplete. In particular, in the expression 'new X()' the initializer
is provided (in 'new X' it is omitted).
 
"An object whose initializer is an empty set of parentheses, i.e.,
(), shall be value-initialized"
 
"To value-initialize an object of type T means ... if T is a
(possibly cv-qualified) class type without a user-provided or deleted
default constructor, then the object is zero-initialized ..."
 
"To zero-initialize an object ... of type T means ... if T is a
scalar type (6.9), the object is initialized to the value obtained by
converting the integer literal 0 (zero) to T ... if T is a (possibly
cv-qualified) non-union class type, each non-static data member ... is
zero-initialized"
 
Anyway, I take my lead from cppreference.com, which is of high quality
and which has already done the hard work. Reading the standard too much
can drive the reader mad. So I am comfortable that even if the
reasoning is wrong the answer (that 'i' is zero initialized) is right.
 
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Oct 12 04:09PM +0100

On 12 Oct 2018 14:31:31 GMT
> as soon as those parentheses (a new-initializer) are supplied.
 
> In the end, I feel too confused for the moment and might
> look into this again later (paragraph hunting in the standard).
 
It really isn't confusing and is set out in TC++PL and cppreference.com.
'new X()' (which has the initializer '()') value-initializes, and 'new
X' doesn't. If you really want to go paragraph hunting (what's wrong
with cppreference.cpp?), here are the references applying in C++14 for
'new X()', in logical order (the order your should read them) not
numerical order:
 
§5.3.4/17.2
§8.5/11
§8.5/8.2
§8.5/6.2
§8.5/6.1
Manfred <noname@invalid.add>: Oct 12 06:10PM +0200

The Standard is obviously the right place to look, as you did.
Out of curiosity, one way to experiment the different initializations is:
 
=====================================================
include <iostream>
 
struct X
{
int i;
};
 
void heap_init()
{
unsigned char a[16*sizeof(int)];
 
for(unsigned char *aa = a; a+sizeof(a) > aa; ++aa)
{
*aa = 0xFF;
}
 
X *p1 = new(a) X;
X *p2 = new(p1+1) X{};
X *p3 = new(p2+1) X();
 
std::cout << "p1->i: " << p1->i << std::endl;
std::cout << "p2->i: " << p2->i << std::endl;
std::cout << "p3->i: " << p3->i << std::endl;
 
p3->~X();
p2->~X();
p1->~X();
 
for(unsigned char *aa = a; a+sizeof(a) > aa; ++aa)
{
*aa = 0xFF;
}
}
 
void stack_init()
{
X x1;
X x2{};
 
std::cout << "x1.i: " << x1.i << std::endl;
std::cout << "x2.i: " << x2.i << std::endl;
}
 
int main()
{
heap_init();
stack_init();
}
 
=====================================================
 
$ c++ -O0 x.cc && ./a.out
p1->i: -1
p2->i: 0
p3->i: 0
x1.i: 32766
x2.i: 0
 
=====================================================
 
ram@zedat.fu-berlin.de (Stefan Ram): Oct 11 11:42PM

>You can implement the idea of an interfaces (similar to Java
>or COM interfaces) by abstract C++ classes which only have
>pure virtual functions.
 
In C++, the meaning of the word "interface" differs from
the meaning of this word in Java or COM. Quotation:
 
|An interface is a contract between two parts of a program.
|Precisely stating what is expected of a supplier of a service
|and a user of that service is essential. Having good
|(easy-to-understand, encouraging efficient use, not
|error-prone, supporting testing, etc.) interfaces is probably
|the most important single aspect of code organization.
C++ Core Guidelines, section I
 
To Bjarne Stroustrup, the interface of a class consists
of its public members. An actual interface class then is
the attempt to separate this interface from a class by
splitting the interface and an implementation between
two different classes.
ram@zedat.fu-berlin.de (Stefan Ram): Oct 11 10:27PM

>They say (Bjarne?) that pure virtual class should not have any
>data/member variables.
 
You can implement the idea of an interfaces (similar to Java
or COM interfaces) by abstract C++ classes which only have
pure virtual functions.
 
The whole idea of an interface is not to lay down a specific
representation. There is nothing that speaks against addding
data to a class with some pure virtual functions, it just
does not represent the idea of an interface very well anymore.
 
>Where is the correct place for age_ assuming that *all animals have
>age*.
 
Maybe in another non-abstract base class that "implements"
the interface.
 
Maybe, you don't need an interface at all, just a normal
base class with some pure virtual functions?
 
Interfaces are not an end in themselves. They are only
implemented when needed.
ram@zedat.fu-berlin.de (Stefan Ram): Oct 12 02:31PM

>"If the new-initializer is omitted, the object is default-initialized." (5.3.4p17).
 
That would be
 
new X
 
, which generates
 
movl $4, %ecx
call _Znwy
 
here. But
 
new X()
 
generates
 
movl $4, %ecx
call _Znwy
movl $0, (%rax)
 
. So the venerable GCC: (GNU) 9.0.0 20180909 (experimental)
with -Ofast -O3 thinks that »i« has to be initialized to zero
as soon as those parentheses (a new-initializer) are supplied.
 
In the end, I feel too confused for the moment and might
look into this again later (paragraph hunting in the standard).
JiiPee <no@notvalid.com>: Oct 12 01:32AM +0100

On 11/10/2018 23:57, Alf P. Steinbach wrote:
>> interfaces should not have data/member variables. Did I misunderstand
>> it?
 
> As a rule of thumb that works.
 
 
ok, so its a rule of thumb. But in each case not to follow blindly. I
was just thinking about this long time. OK, good to know I was pretty
much on right track (I also thought It can be ok).
 
 
 
> I guess the main advice is to know the /rationale/ of the rules, why
> they are recommendations that generally work out OK, so that one can
> decide on an informed basis whether to follow them in any given case.
 
Yes, and that was clarified here.
JiiPee <no@notvalid.com>: Oct 12 01:35AM +0100

On 11/10/2018 23:27, Stefan Ram wrote:
> There is nothing that speaks against addding
> data to a class with some pure virtual functions, it just
> does not represent the idea of an interface very well anymore.
 
 
Sure, and maybe then its not even meant to be an interface.
 
But was thinking also should this Animal thing be changed so that it is
a pure interface? like somebody said, we could have a AnimalBase which
would be pure. and Animal inherited maybe from it? I was actually
thinking about this also
JiiPee <no@notvalid.com>: Oct 12 01:41AM +0100

On 11/10/2018 23:10, Mr Flibble wrote:
> Perhaps you should make talk() pure virtual instead?
 
 
I was thinking if the animal cannot talk then no need to implement this
function. but yes, its not that simple, because maybe for debugging
purposes we want that talk() also for them.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Oct 12 12:57AM +0200

On 12.10.2018 00:03, JiiPee wrote:
> They say (Bjarne?) that pure virtual class should not have any
> data/member variables.
 
"Pure virtual class" is not standard terminology. I think you mean a
pure interface class. Which is not standard C++ terminology, but a
descriptive term that indicates how the class is used.
 
A pure interface will usually not have data members, but it's a feature
of C++ that it /can/ have data members. One reason to not have data
members is that without data members, one can inherit from that
interface multiple times with no ill effects, e.g., an animal will not
wind up with multiple different ages. To avoid such problems, with data
members one is essentially restricted to either single inheritance, or
virtual inheritance, and the latter carries some run time overhead. But
for any given case this restriction may not necessarily matter, and it
must be balanced against the advantages such as simplicity with data
members versus complexity without, i.e. the usefulness of data members.
 
Non-virtual member functions can also be useful, e.g. as wrappers that
check preconditions and postconditions for the called virtual functions.
 
 
> private:
>     int age_;
> };
 
Consider what happens as time goes by. The animals will not age. If you
want them to have age values that reflect the passage of time in the
real world, you can use a birthdate (including the year, of course).
 
 
> age*. So lets assume that 100% all animals will have age-variable (they
> need it). But its logical that Animal is pure virtual. So, where should
> age_ belong to if not inside Animal class?
 
Putting the known common implementation and/or implementation support in
the base is generally OK.
 
There can be reasons not to do it, such as supporting general use of the
interface for arbitrary classes (you'd not want to impose per-instance
overhead on those not-really-animal classes), including, as mentioned,
general multiple inheritance, or, in a different direction, avoiding
headers that the implementation part needs. But it's generally OK.
 
 
> Or did I misunderstand something? I think somebody said pure virtual
> interfaces should not have data/member variables. Did I misunderstand it?
 
As a rule of thumb that works.
 
But in any given case one should, if possible, do what seems reasonable
for the case at hand, preferably after /informed/ consideration, but in
the worst case just gut feeling, and not blindly follow a rule of thumb.
 
Following mechanical rules that have worked for others is a nice
default, generally not a bad idea, but if software could be developed
only that way it would have been developed by cheap software robots.
 
I guess the main advice is to know the /rationale/ of the rules, why
they are recommendations that generally work out OK, so that one can
decide on an informed basis whether to follow them in any given case.
 
And that's what you're doing now, asking for rationale, so you're fine.
 
 
Cheers!,
 
- Alf
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Oct 12 01:00AM +0200

On 12.10.2018 00:57, Alf P. Steinbach wrote:
> [sniop]
> A pure interface will usually not have data members, but it's a feature
> of C++ that it /can/ have data members.
 
I meant to write, an *interface*.
 
When it has a data member it's no longer pure.
 
 
Cheers!,
 
- Alf
Bo Persson <bop@gmb.dk>: Oct 12 11:11AM +0200

On 2018-10-12 02:32, JiiPee wrote:
 
> ok, so its a rule of thumb. But in each case not to follow blindly. I
> was just thinking about this long time. OK, good to know I was pretty
> much on right track (I also thought It can be ok).
 
Some of these rules are derived from the use of other languages, where
an interface just cannot have data members. That makes it easy (for
those languages) to make it a hard rule. Because that is the only
option. :-)
 
C++ being a multi-paradigm language lets you make your own choices. One
possible choice is to be more pragmatic and not blindly follow the
rules/guidelines when they seem like a bad fit for the case at hand.
 
 
Bo Persson
JiiPee <no@notvalid.com>: Oct 12 11:36AM +0100

On 12/10/2018 10:11, Bo Persson wrote:
 
> C++ being a multi-paradigm language lets you make your own choices.
> One possible choice is to be more pragmatic and not blindly follow the
> rules/guidelines when they seem like a bad fit for the case at hand.
 
well said
JiiPee <no@notvalid.com>: Oct 12 11:42AM +0100

On 12/10/2018 10:11, Bo Persson wrote:
 
> C++ being a multi-paradigm language lets you make your own choices.
 
to be honest, this is why I liked C++, its not so strict to certain
"syntax", but you can do your own things there if you want. (obviously
needs to be careful not to go too far but follow the recommendations).
thats why I also like(d) assembly language: you can do even more tricks
if you want/need :).
And this is why I never really like Basic language (although started
with it): it does not have pointers and is quite limited language. I
wanted "all" :). Currently C++ is best language in that sense - it lets
you to do your own tricks most. (Of course Basic language has also its
place and so on...I understand).
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: