- "Rust vs. C++ Comparison" - 3 Updates
- Allocating with new but freeing the memory with free - 3 Updates
- Default values or undefined values? - 8 Updates
- About placing member variable into a pure virtual base class - 3 Updates
- About placing member variable into a pure virtual base class - 8 Updates
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:
Post a Comment