- "C++ on the Move" by Darryl K. Taft - 10 Updates
- Pass by rvalue reference - 1 Update
- Why no structured bings in catch()? - 7 Updates
- reference to reference (Type &&) - 5 Updates
- Functions and Global Variables defined in Libraries - 2 Updates
Paavo Helde <eesnimi@osa.pri.ee>: Mar 08 08:40AM +0200 08.03.2023 01:10 Richard kirjutas: > do it. If I started bitching about Java and when asked to put up or > shut up, I started showing JavaScript, people would rightly laugh at > me. +100 |
"Öö Tiib" <ootiib@hot.ee>: Mar 07 11:21PM -0800 On Wednesday, 8 March 2023 at 00:26:14 UTC+2, Lynn McGuire wrote: > use Rust…'], C++ must evolve or be left behind. The question is, at what > price?" he said." > https://twitter.com/markrussinovich/status/1571995117233504257?lang=en Most people agree that C++ contains too lot of features. They only differ by opinion where to cut. I would put most effort into places where it says "undefined behavior". I think half of such places can be replaced with "program is ill formed", "std::terminate is called" or one of the features that lead to described situation can be cut out (as badly thought thru). |
scott@slp53.sl.home (Scott Lurndal): Mar 08 04:10PM >"undefined behavior". I think half of such places can be replaced with=20 >"program is ill formed", "std::terminate is called" or one of the features >that lead to described situation can be cut out (as badly thought thru). The nice thing about C++ is that one need not use any of the new crap. |
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Mar 08 09:52AM -0800 > "undefined behavior". I think half of such places can be replaced with > "program is ill formed", "std::terminate is called" or one of the features > that lead to described situation can be cut out (as badly thought thru). I'd be interested in seeing some cases of undefined behavior that could reasonably be detected at compile time or at run time. I'm sure there are some, but I'd be surprised it were as many as half. Just one example: Signed integer overflow has undefined behavior, and defining it would require runtime checks. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for XCOM Labs void Void(void) { Void(); } /* The recursive call of the void */ |
Malcolm McLean <malcolm.arthur.mclean@gmail.com>: Mar 08 10:18AM -0800 On Wednesday, 8 March 2023 at 17:53:09 UTC, Keith Thompson wrote: > are some, but I'd be surprised it were as many as half. > Just one example: Signed integer overflow has undefined behavior, and > defining it would require runtime checks. Not on the vast majority of platforms. However you'd have to define the behaviour as a two's complement wrap. |
"Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Mar 08 07:20PM +0100 On 2023-03-08 6:52 PM, Keith Thompson wrote: > are some, but I'd be surprised it were as many as half. > Just one example: Signed integer overflow has undefined behavior, and > defining it would require runtime checks. I guess you meant to write, "detecting it", not "defining it". Defining signed overflow as wrap-around requires no runtime checks, now that C++ integers are guaranteed two's complement. Some optimization opportunities would be lost, but maybe others gained. - Alf |
David Brown <david.brown@hesbynett.no>: Mar 08 07:47PM +0100 On 08/03/2023 17:10, Scott Lurndal wrote: >> "program is ill formed", "std::terminate is called" or one of the features >> that lead to described situation can be cut out (as badly thought thru). > The nice thing about C++ is that one need not use any of the new crap. Or one need not use the old crap, and can use the new better features instead. Or a mixture. Or all. Or nearly none. It's a big language, and a big library - few people are going to have use for all of it, but the subset you find useful will vary widely from person to person. |
James Kuyper <jameskuyper@alumni.caltech.edu>: Mar 08 02:10PM -0500 On 3/8/23 13:20, Alf P. Steinbach wrote: > On 2023-03-08 6:52 PM, Keith Thompson wrote: ... >> Just one example: Signed integer overflow has undefined behavior, and >> defining it would require runtime checks. > I guess you meant to write, "detecting it", not "defining it". No, he meant "defining it". If they were to choose to define the behavior of signed integer overflow, then on platforms where the defined behavior was not the same as that which would naturally occur, run-time checks would be required to change the behavior. |
Michael S <already5chosen@yahoo.com>: Mar 08 11:21AM -0800 On Wednesday, March 8, 2023 at 6:10:28 PM UTC+2, Scott Lurndal wrote: > >"program is ill formed", "std::terminate is called" or one of the features > >that lead to described situation can be cut out (as badly thought thru). > The nice thing about C++ is that one need not use any of the new crap. That 's not 100% true. Two example of [not so] new non-crap libraries that are entangled with [not so] new crap - std::chrono and std::random. The former is infected by rational numbers crap. The later is soiled both with <functional> and and with std::ref. And both of them misuse operator overloading. Not that I am aware of many places in standard library where operator overloading is not misused. |
David Brown <david.brown@hesbynett.no>: Mar 08 08:45PM +0100 On 08/03/2023 19:18, Malcolm McLean wrote: >> defining it would require runtime checks. > Not on the vast majority of platforms. However you'd have to define the > behaviour as a two's complement wrap. Wrapping is not the only option. But since wrapping is the most useless behaviour for signed integer overflow, doing something helpful (such as the suggested call to std::terminate, or other error message to aid debugging) /would/ require run-time checks. |
Pawel Por <porparek@gmail.com>: Mar 08 10:29AM -0800 Thank you for response. > Why? The code you provided does not use assignment operator at all. Why > would you expect assignment operator to be called? Right, I expect the move constructor to be called - sorry for confusion. >> I expect the Dog::Dog(Dog&&) to be called (sorry for confusion) >But it _is_ called. Here's the output I get from your code It is the std::move that forces the move constructor to be called. For me it looks like the argument is passed by lvalue reference to the MyList<T>::push_front(T&&) function. I've modified the code to show this: #include <iostream> #include <forward_list> #include <utility> template <typename T> void p(const T &v) { std::cout << v << std::endl; } struct Dog { Dog() { p(__PRETTY_FUNCTION__); } Dog(const Dog&) { p(__PRETTY_FUNCTION__); } Dog(Dog&&) { p(__PRETTY_FUNCTION__); } Dog& operator=(const Dog&) { p(__PRETTY_FUNCTION__); return *this; } Dog& operator=(Dog &&) { p(__PRETTY_FUNCTION__); return *this; } }; template<typename T> struct MyList { void push_front(T &&v) { p(__PRETTY_FUNCTION__); p("before std::move"); T x = std::move( v ); p("after std::move"); (void) x;} }; int main() { MyList<Dog> ml; std::forward_list<Dog> fl; Dog dog; p("ml.push_front"); ml.push_front(std::move(dog)); p("fl.push_front"); fl.push_front(std::move(dog)); } Here is the output: Dog::Dog() ml.push_front void MyList<T>::push_front(T&&) [with T = Dog] before std::move Dog::Dog(Dog&&) after std::move fl.push_front Dog::Dog(Dog&&) I expect the Dog's move constructor to be called when passing an argument to MyList<T>::push_front(T&&) |
Muttley@dastardlyhq.com: Mar 08 10:04AM Just discovered that I can't do this in C++17: throw pair<string,int>("hello",123) catch(auto &[str,val]) { } Is there a good reason why this can't be implemented? |
"Öö Tiib" <ootiib@hot.ee>: Mar 08 03:23AM -0800 > { > } > Is there a good reason why this can't be implemented? Hmm I can't think of any way to implement it. Can you? How can the compiler know what that exception could possibly be? It has none of information at all. The throw can be anywhere far up stack in dynamically linked library. So how to bind to unlimited kinds of whatever (struct {? a, ? b;} , std::array<?,2>, std::tuple<?,?>, std::pair<?, ?>, etc.) structurally by current language rules? |
Muttley@dastardlyhq.com: Mar 08 11:45AM On Wed, 8 Mar 2023 03:23:52 -0800 (PST) >Hmm I can't think of any way to implement it. Can you? >How can the compiler know what that exception could possibly be? >It has none of information at all. The throw can be anywhere far up Of course it has the information. It knows whats been thrown so it knows if it can be captured in a structure binding. How does it know how to set a binding from the return value of a function then? >stack in dynamically linked library. So how to bind to unlimited kinds >of whatever (struct {? a, ? b;} , std::array<?,2>, std::tuple<?,?>, >std::pair<?, ?>, etc.) structurally by current language rules? You could use the same argument for structured bindings anywhere. |
Sam <sam@email-scan.com>: Mar 08 07:13AM -0500 > >It has none of information at all. The throw can be anywhere far up > Of course it has the information. It knows whats been thrown so it knows > if it can be captured in a structure binding. It only knows what's thrown at runtime. Not at compile time. It is fundamental to C++: the types of all objects must be known at compile time. "auto" doesn't change that. All that "auto" is, is an alias that says, in a matter of speaking "unchanged", or "same as whatever you're assigning me". When a function's return value is declared as "auto", the compiler looks at the actual "return" statements, and uses whatever they do. If only the declaration is available you'll skate by until either the function definition is available, or until something tries to use its return value in any way. > How does it know how to > set a binding from the return value of a function then? Because it knows the actual type of the object that the function returns, as long as its declared. Try to do the same structural binding with a function that, itself, is declared as returning an auto, without the function's body being compiled. See how much progress you'll make. > >of whatever (struct {? a, ? b;} , std::array<?,2>, std::tuple<?,?>, > >std::pair<?, ?>, etc.) structurally by current language rules? > You could use the same argument for structured bindings anywhere. No, you can't. |
Muttley@dastardlyhq.com: Mar 08 04:21PM On Wed, 08 Mar 2023 07:13:05 -0500 >> Of course it has the information. It knows whats been thrown so it knows >> if it can be captured in a structure binding. >It only knows what's thrown at runtime. Not at compile time. It is It knows what is thrown at runtime. It knows what *could* be thrown at compile time. And if it knows what could be thrown and what catch statements are encompassing those throws then it could compile in suitable types for an auto in the catch. |
Bonita Montero <Bonita.Montero@gmail.com>: Mar 08 06:28PM +0100 > { > } > Is there a good reason why this can't be implemented? With the thrown object there's some type information passed along to verify if it fits against the type being catched. If you want to catch sth. auto-ish you won't have a strong type-match. So this doesn't work. |
Bo Persson <bo@bo-persson.se>: Mar 08 07:21PM +0100 >> It only knows what's thrown at runtime. Not at compile time. It is > It knows what is thrown at runtime. > It knows what *could* be thrown at compile time. But it doesn't. The called functions could be recompiled later, with new exceptions added. Or a new version of a library could be installed. How is the catch to know that? > And if it knows what could be thrown and what catch statements are encompassing > those throws then it could compile in suitable types for an auto in the catch. Perhaps we need a templated catch that is instantiated at runtime? That would be a novelty. |
Muttley@dastardlyhq.com: Mar 08 09:21AM On Wed, 8 Mar 2023 00:10:43 +0200 >rvalue whose final state would not be important anyway, or we use >std::move() to explicitly declare we do not care about the final state >of the object. Thats fine, until its used in a library and someone doesn't look at the code so don't realise the object they passed in is now invalid. Yes thats a fairly unlikely scenario but something that needs to be considered when using move. Will someone use your code who isn't aware of what you've done? |
Paavo Helde <eesnimi@osa.pri.ee>: Mar 08 02:41PM +0200 > code so don't realise the object they passed in is now invalid. Yes thats > a fairly unlikely scenario but something that needs to be considered when > using move. Will someone use your code who isn't aware of what you've done? Care to bring an example? I have hard time figuring out how one could get a moved-away object via rvalue references inadvertently. |
Muttley@dastardlyhq.com: Mar 08 04:26PM On Wed, 8 Mar 2023 14:41:30 +0200 >> using move. Will someone use your code who isn't aware of what you've done? >Care to bring an example? I have hard time figuring out how one could >get a moved-away object via rvalue references inadvertently. #include <iostream> #include <string> using namespace std; void myfunc(string &s1) { string s2 = move(s1); } int main() { string s1 = "hello"; myfunc(s1); cout << s1 << endl; return 0; } |
"Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Mar 08 06:08PM +0100 > cout << s1 << endl; > return 0; > } Entirely safe code. A move from any standard library object leaves the object in a well-defined state. The originally proposed rules didn't completely guarantee all desired safety, but as I recall Scott Meyers posted in this very group about it, and after some discussion reasonable compromise was reached. :) - Alf PS: You don't need the `return 0;`; that's the default for `main` in both C and C++. |
Paavo Helde <eesnimi@osa.pri.ee>: Mar 08 07:23PM +0200 > cout << s1 << endl; > return 0; > } There is no rvalue reference in this example, only a non-const lvalue reference which is known to be error-prone and tricky to use. Use rvalue references instead: #include <iostream> #include <string> using namespace std; void myfunc(string &&s1) { string s2 = move(s1); } int main() { string s1 = "hello"; // myfunc(s1); // does not compile myfunc(std::move(s1)); // ok, explicit move cout << s1 << endl; return 0; } |
Frederick Virchanza Gotham <cauldwell.thomas@gmail.com>: Mar 08 08:34AM -0800 I've been doing some major tinkering. The entry point of an executable is '_start'. So, first I wrote a new entry point in x64 assembler that could differentiate between GUI mode and console mode depending upon the value of 'argc': ; This file contains x86_64 assembler for NASM, also known as x64. ; This file contains two functions: ; static void print8bytes(uint64_t eight_chars,uint64_t new_line); ; extern void pre_start(int argc); section .text print8bytes: ; This is a function that returns void ; Two parameters: ; r9: The 8-byte string to print ; r8: If true, prints a trailing new line ; save all the register values we're going to use push rax push rsi push rdi push rdx ;zero out the registers we are going to need xor rax, rax xor rsi, rsi xor rdi, rdi xor rdx, rdx ;write(int fd, char *msg, unsigned int len) mov al, 1 add di, 1 mov rsi, r9 push rsi mov rsi, rsp mov dl, 8 ; Print 8 bytes at a time syscall pop rsi cmp r8, 1 ; check if r8 is true or false jl no_new_line ;zero out the registers we are going to need xor rax, rax xor rsi, rsi xor rdi, rdi xor rdx, rdx ;write(int fd, char *msg, unsigned int len) mov al, 1 add di, 1 mov rsi, 0x000000000000000a ; new line push rsi mov rsi, rsp mov dl, 1 ; Print just one byte syscall pop rsi no_new_line: ; just a jump label - not a function name pop rdx pop rdi pop rsi pop rax ret global pre_start:function pre_start: ; The 'argc' argument to 'main' is on the top of the stack so ; we will use the frame pointer 'rbp' to keep track of it. push rbp mov rbp, rsp push r9 ; save because we'll use it - pop it back later push r8 ; save because we'll use it - pop it back later mov r8, 0 ; false = don't put trailing new line mov r9, 0x3d3d3d3d3d3d3d3d ; "========" call print8bytes call print8bytes call print8bytes mov r9, 0x6174735f65727020 ; " pre_sta" call print8bytes cmp qword[rbp+8], 2 ; check if argc < 2 jl $+2+10+2 ; if argc < 2 then we want GUI mode mov r9, 0x646d63202d207472 ; "rt - cmd" jmp $+2+10 ; skip the next 10-byte instruction mov r9, 0x495547202d207472 ; "rt - GUI" call print8bytes mov r9, 0x3d3d3d3d3d3d3d3d ; "========" call print8bytes call print8bytes mov r8, 1 ; true = put trailing new line call print8bytes pop r9 pop r8 mov rsp, rbp pop rbp extern _start jmp _start If you see the last line there, I jump straight into _start. So then I build my program with a new entry point as follows: g++ -o prog prog.cpp object_file_from_assembler.o -e pre_start When I run it at the command line, the first thing I get is: ======================== pre_start - GUI======================== and then it continues execution as normal. No problems. So then the next thing I did was I used 'patchelf' to remove the NEEDED for the graphical user interface library: patchelf --remove-needed libgtk-3.so.0 ./prog And then I tried to run it again, but this time around I got back: ./ssh: symbol lookup error: ./ssh: undefined symbol: gtk_true This means that the program falls over ***before*** the entry point is reached. So the part of the Linux operating system that loads executable files is not even going into the entry point for my program, it's falling over before then. I need to stop this happening some how. Perhaps I can put dummy values in the GOT table so that the loader doesn't think they're null? |
"Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Mar 08 06:17PM +0100 On 2023-03-08 5:34 PM, Frederick Virchanza Gotham wrote: > [snip] > So the part of the Linux operating system that loads executable files > is not even going into the entry point for my program So, you were not talking about Windows' console and GUI subsystems, but about general application behavior. Still the solution with two separate executables, perhaps with one invoking the other, seems very much preferable to mucking about with entry points and whatever, except if you're doing that for the joy of hacking? I believe in Linux the average user will have no problem relating to separate executables. --- In Windows you can check the executable's subsystem by inspecting the bytes of the loaded image of the executable. The start address of that image is available from `GetModuleHandle(0)`. Happy hacking! :) - Alf |
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