- Differences between C and C++ - 6 Updates
- undexpected modification of string array - 2 Updates
- Function overloading - 3 Updates
- Main thread distributes workload to worker threads, then they all rendezvous later - 3 Updates
- ostringstream performance - 5 Updates
- Is a char array initializer a "string literal"? - 5 Updates
- "Carbon, a new programming language from Google, aims to be C++ successor" - 1 Update
| Muttley@dastardlyhq.com: Jul 27 07:52AM On Tue, 26 Jul 2022 11:59:21 -0700 >>>> >>>lvalue, so `&(struct s){1}` is not valid. >>>> >> Certainly doesn't work with Clang though you'd think if the same >compiler : : >Most C++ compilers are non-conforming by default, quietly accepting >extensions that are incompatible with the standard. All conforming C++ >compilers provide a way to issue all required diagnostics. I'm aware of all this. My point is why are some C semantics considered compilable (albeit with warnings) but the original example of &(struct s){1} isn't and causes an error even though its perfectly legal in C. |
| "Öö Tiib" <ootiib@hot.ee>: Jul 27 01:56AM -0700 > I'm aware of all this. My point is why are some C semantics considered > compilable (albeit with warnings) but the original example of &(struct s){1} > isn't and causes an error even though its perfectly legal in C. It is because while the compilers implemented extension of supporting compound literals almost like in C, the result in those extensions is temporary whose lifetime will last only to end of full-expression. Taking address of temporary is illegal and so &(struct s){1} is illegal. Why they did not implement the semantics fully like in C is because they used it like kind of alternative syntax sugar to list-initialization. Since C++14 however they can not heap-allocate initializer-lists (and did not do it even before C++14). So the compound literal extension is temporary for ease of implementation. Some of compilers that do it are open source so if you want you can perhaps implement more close to C extension to those. |
| Muttley@dastardlyhq.com: Jul 27 02:51PM On Wed, 27 Jul 2022 01:56:23 -0700 (PDT) >It is because while the compilers implemented extension of supporting >compound literals almost like in C, the result in those extensions is >temporary whose lifetime will last only to end of full-expression. Taking The expressions lifetime - and hence the temporary shouldn't end until the function being called returns. It should remain on the stack of the calling function which is probably what happens in C. >for ease of implementation. Some of compilers that do it are open source >so if you want you can perhaps implement more close to C extension >to those. Why? Since they're also already C compilers the code to do it already exists inside them and is probably a case of setting an internal flag to call it. |
| Ben Bacarisse <ben.usenet@bsb.me.uk>: Jul 27 05:33PM +0100 > Actually "abc" is an array-of-char (or array-of-const-char in the latter > case). You can discern this by eg. printing what sizeof("12345") is > (quite a nice quiz question). Yes, I should have added "converts to in most contexts" because that's usually how the difference gets spotted. To be clear, the string literal above has type char[4] in C and const char[4] in C++. -- Ben. |
| Paul N <gw7rib@aol.com>: Jul 27 10:09AM -0700 On Monday, July 25, 2022 at 2:14:50 PM UTC+1, Juha Nieminen wrote: > syntax that compiles in one but not the other. I'm talking about code that > does compile as both C and C++, but will be interpreted or behave > differently depending on which (and this makes them incompatible). As I understand it, the two languages have quite different philosophies. In BCPL there is a stated aim of eliminating hidden overhead. There seems nothing in the history of C to suggest that this aim was dropped, certainly B was developed on a very spartan machine. In contrast the aim in C++ is to try to hide the underlying details. For example, in C, a = b + c is a straight-forward addition, though depending on the types it might be a floating-point addition or it might involve a hidden multiplication by a pointer size. In C++, a = b + c could be anything - for instance, it might concatenate two files to form a third one, involving thousands of disk accesses. |
| Bo Persson <bo@bo-persson.se>: Jul 27 07:28PM +0200 On 2022-07-27 at 19:09, Paul N wrote: >> does compile as both C and C++, but will be interpreted or behave >> differently depending on which (and this makes them incompatible). > As I understand it, the two languages have quite different philosophies. In BCPL there is a stated aim of eliminating hidden overhead. There seems nothing in the history of C to suggest that this aim was dropped, certainly B was developed on a very spartan machine. In contrast the aim in C++ is to try to hide the underlying details. Yes, we call that abstraction. :-) Bjarne uses an onion as his metafor. We don't want to see all the way to the core all the time. > For example, in C, a = b + c is a straight-forward addition, though depending on the types it might be a floating-point addition or it might involve a hidden multiplication by a pointer size. In C++, a = b + c could be anything - for instance, it might concatenate two files to form a third one, involving thousands of disk accesses. I have never understood why this is a problem. In C you can write a = add(b, c) and it can do anything. How is that easier to see through than using the + operator? |
| Jivanmukta <jivanmukta@poczta.onet.pl>: Jul 27 06:32PM +0200 I have object of my class source_file: class source_file { private: std::wstring source_file_path; int current_source_line_no; bool inside_php, start_inside_php; int num_source_lines, too_long_line_number; std::vector<std::string> source_lines; std::vector<std::pair<int, std::string>> tokenized_lines; std::vector<std::pair<int, std::string>>::const_iterator current_tokenized_lines_iter; size_t max_line_len, too_long_line_len, max_found_line_len; public: source_file(size_t max_line_length = 0) { // 0 means 'no limit' max_line_len = max_line_length; too_long_line_len = 0; max_found_line_len = 0; current_source_line_no = -1; num_source_lines = 0; current_tokenized_lines_iter = tokenized_lines.end(); too_long_line_number = 0; inside_php = start_inside_php = false; } size_t get_max_found_line_length() const { return max_found_line_len; } size_t get_too_long_line_length() const { return too_long_line_len; } int get_too_long_line_number() const { return too_long_line_number; } bool open(std::wstring in_file_path); void close() { source_lines.clear(); tokenized_lines.clear(); too_long_line_len = 0; max_found_line_len = 0; num_source_lines = 0; current_source_line_no = -1; } void rewind() { // go to begin of file current_source_line_no = -1; current_tokenized_lines_iter = tokenized_lines.begin(); inside_php = start_inside_php = false; } bool get_next_line(std::string &line); bool change_current_line(std::string line, bool ltrim_line); void ltrim_current_line(); void get_contents(std::vector<std::string> &contents); bool change_file_with_contents(const std::vector<std::string> &contents, unsigned int defines_line_num = 0, unsigned int defines_num_lines = 0); void remove_magic_str(); void write(std::wstring out_file_path) const { std::ofstream out_file(shortwstr2str(out_file_path)); for (std::string line : source_lines) { out_file << line << std::endl; } } void tokenize_file(std::string token_name_delim_str); bool get_next_line_with_tokenized(std::string &line, std::string &tokenized_line); }; The problem is that in some moment of time source_lines[318] is unexpectedly modified, I don't know why and when, although the file is correctly loaded to source_lines[], I mean open() works fine and some time later get_next_line() returns spoilt string. Conditional breakpoints don't work (I use VSCodium). How to find the moment of modification of source_line[318]? |
| Ralf Fassel <ralfixx@gmx.de>: Jul 27 07:20PM +0200 * Jivanmukta <jivanmukta@poczta.onet.pl> | The problem is that in some moment of time source_lines[318] is | unexpectedly modified, --<snip-snip>-- | How to find the moment of modification of source_line[318]? Use valgrind or similar. R' |
| Bonita Montero <Bonita.Montero@gmail.com>: Jul 27 04:10PM +0200 Am 21.07.2022 um 02:22 schrieb Lynn McGuire: > int5, int int6, int int7, int int8, int int9); > std::vector <int> tuple (int int1, int int2, int int3, int int4, int > int5, int int6, int int7, int int8, int int9, int int10); You can have that easier: template<typename To, typename ... Ts> vector<To> myTuple( Ts &&... params ) requires (convertible_to<Ts, To> && ...) { vector<To> vt; vt.reserve( sizeof ...(Ts) ); auto make_row = [&]<size_t ... Indices>( index_sequence<Indices ...> ) { ((Indices, vt.emplace_back( params )), ...); }; make_row( make_index_sequence<sizeof ...(Ts)>() ); return vt; } Works with an arbitrary number of parameters. |
| Bonita Montero <Bonita.Montero@gmail.com>: Jul 27 04:11PM +0200 Am 27.07.2022 um 16:10 schrieb Bonita Montero: > make_row( make_index_sequence<sizeof ...(Ts)>() ); > return vt; > } Now it's complete, I fogot to forward: template<typename To, typename ... Ts> vector<To> myTuple( Ts &&... params ) requires (convertible_to<Ts, To> && ...) { vector<To> vt; vt.reserve( sizeof ...(Ts) ); auto make_row = [&]<size_t ... Indices>( index_sequence<Indices ...> ) { ((Indices, vt.emplace_back( forward<Ts>( params ) )), ...); }; make_row( make_index_sequence<sizeof ...(Ts)>() ); return vt; } |
| Bonita Montero <Bonita.Montero@gmail.com>: Jul 27 04:35PM +0200 Am 27.07.2022 um 16:10 schrieb Bonita Montero: > return vt; > } > Works with an arbitrary number of parameters. This is even more convenient: template<typename ... Ts> requires (sizeof ...(Ts) >= 1) && (convertible_to<Ts, tuple_element_t<0, tuple<Ts ...>>> && ...) vector<tuple_element_t<0, tuple<Ts ...>>> myTuple( Ts &&... params ) { vector<tuple_element_t<0, tuple<Ts ...>>> vt; vt.reserve( sizeof ...(Ts) ); auto make_row = [&]<size_t ... Indices>( index_sequence<Indices ...> ) { ((Indices, vt.emplace_back( forward<Ts>( params ) )), ...); }; make_row( make_index_sequence<sizeof ...(Ts)>() ); return vt; } |
| Frederick Virchanza Gotham <cauldwell.thomas@gmail.com>: Jul 27 03:51AM -0700 On Monday, July 25, 2022 at 11:40:50 PM UTC+1, Chris M. Thomasson wrote: > How are you parallelizing a single block? I read 384 bytes in from the files, into a big buffer like this: char buf[6][64]; Each of the six worker threads accesses the array like this: char (&data)[64] = buf[thread_id]; Encrypt_Data_In_Place(data); So the main thread populates the global array, "buf", sets the workers to work, waits for them all to finish, and then loads another 384 bytes into "buf". You get me? (In a previous post I wrote 8kb with 8 threads but I was just picking nice round numbers. Really I have 6 threads each processing 64 bytes at a time -- yeah I should probably increase that massively). |
| Paavo Helde <eesnimi@osa.pri.ee>: Jul 27 02:46PM +0300 27.07.2022 13:51 Frederick Virchanza Gotham kirjutas: > So the main thread populates the global array, "buf", sets the workers to work, waits for them all to finish, and then loads another 384 bytes into "buf". > You get me? > (In a previous post I wrote 8kb with 8 threads but I was just picking nice round numbers. Really I have 6 threads each processing 64 bytes at a time -- yeah I should probably increase that massively). If you are doing things like this, you should also turn attention to cache lines and false sharing. See e.g. std::hardware_destructive_interference_size ("https://en.cppreference.com/w/cpp/thread/hardware_destructive_interference_size") 64 bytes separation is probably just fine (for the current hardware, that is). |
| scott@slp53.sl.home (Scott Lurndal): Jul 27 02:02PM >("https://en.cppreference.com/w/cpp/thread/hardware_destructive_interference_size") >64 bytes separation is probably just fine (for the current hardware, >that is). There is hardware out in the real world with 128-byte cache lines. Primarily in the DPU arena. |
| Manfred <noname@add.invalid>: Jul 27 02:08AM +0200 On 7/26/2022 6:00 AM, Malcolm McLean wrote: > I don't know because it's ages since I've looked at a modern processor in > much detail, but the real cost could be much higher than the cost of the > extra instructions. The cost of /conditional/ branching is significant in modern architectures. However, a virtual function call is not this case: it's a deterministic indirection that should be correctly followed (it's not really a prediction since its destination is known in advance) by the processor. As Scott says, one relevant factor is locality. Another relevant factor, when it comes to optimization, is that the compiler cannot inline virtual functions (unless the concrete type is actually known at the point of call). |
| "Öö Tiib" <ootiib@hot.ee>: Jul 26 07:49PM -0700 On Wednesday, 27 July 2022 at 03:08:33 UTC+3, Manfred wrote: > Another relevant factor, when it comes to optimization, is that the > compiler cannot inline virtual functions (unless the concrete type is > actually known at the point of call). That is the case with boost::base_collection<Base> that keeps the elements in sub-containers of concrete type. So for example when element is accessed through local_iterator<Derived> the compiler knows that type is Derived, despite container is polymorphic. |
| Frederick Virchanza Gotham <cauldwell.thomas@gmail.com>: Jul 27 03:54AM -0700 On Wednesday, July 27, 2022 at 1:08:33 AM UTC+1, Manfred wrote: > Another relevant factor, when it comes to optimization, is that the > compiler cannot inline virtual functions (unless the concrete type is > actually known at the point of call). If the concrete type is known at the point of call, then there's no overhead. If the concrete type is **not** known at the point of call, for example you're using a pointer to the Base class type, then the virtualness is actually needed, and it has been implemented the best way possible. Actually I'm really convincing myself here that I should just mark every method virtual. |
| Paavo Helde <eesnimi@osa.pri.ee>: Jul 27 03:00PM +0300 27.07.2022 13:54 Frederick Virchanza Gotham kirjutas: >> compiler cannot inline virtual functions (unless the concrete type is >> actually known at the point of call). > If the concrete type is known at the point of call, then there's no overhead. Only if all code is visible to the optimizer, and the code is simple enough for the optimizer, and the optimizer actually decides to optimize that away. With this iostreams example, none of that seems to happen. Even clearing the stringstream buffer with oss.str(""); is taking more time than the whole Bonita's "manual" branch. > If the concrete type is **not** known at the point of call, for example you're using a pointer to the Base class type, then the virtualness is actually needed, and it has been implemented the best way possible. > Actually I'm really convincing myself here that I should just mark every method virtual. That language has another name. |
| scott@slp53.sl.home (Scott Lurndal): Jul 27 01:57PM >> much detail, but the real cost could be much higher than the cost of the >> extra instructions. >The cost of /conditional/ branching is significant in modern architectures. Not generally. Branch history buffers, prediction hardware and other facilities in the hardware interact with the speculation hardware to speculate down the likely path. They work pretty well in general, albeit speculation has it's own shortcomings vis-a-vis security. Performance or security but not necessarily both. |
| Andrey Tarasevich <andreytarasevich@hotmail.com>: Jul 26 05:56PM -0700 On 7/26/2022 12:57 AM, Juha Nieminen wrote: > char str[] = "hello"; > can that "hello" even be considered a "string literal", or should it > be classified as something else? Yes, it is a string literal. I.e. formally it is an independent object with static storage duration, independent and separate from `str` in your example. > array-of-const-char (of a size needed to store the contents of the > string literal). So for example the type of "hello" is const char[6]. > However, you can't initialize an array with another array. But you _can_ initialize a char array with a string literal. A special exception is deliberately made for this specific case in C and C++ standards. They explicitly state that you _can_ initialize a char array with a string literal and explicitly specify the semantics of such initialization. -- Best regards, Andrey |
| Keith Thompson <Keith.S.Thompson+u@gmail.com>: Jul 26 07:24PM -0700 > Yes, it is a string literal. I.e. formally it is an independent object > with static storage duration, independent and separate from `str` in > your example. It is a string literal, i.e., it is a source code token starting and ending with a '"' character. The corresponding object with static storage duration is not a string literal. It doesn't exist until execution time. [...] -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for Philips void Void(void) { Void(); } /* The recursive call of the void */ |
| Juha Nieminen <nospam@thanks.invalid>: Jul 27 07:40AM > <url: https://en.cppreference.com/w/cpp/types/decay>, > But if you make a reference `auto&`, then there must be a more exact > match with the initializer type. Is there a good reason that they added such confusing needless complexity to the keyword? What's the purpose of such inconsistent behavior? |
| "Öö Tiib" <ootiib@hot.ee>: Jul 27 01:17AM -0700 On Wednesday, 27 July 2022 at 10:41:17 UTC+3, Juha Nieminen wrote: > > match with the initializer type. > Is there a good reason that they added such confusing needless complexity > to the keyword? What's the purpose of such inconsistent behavior? They reused the rules of template argument deduction. I am not 100% sure why but most likely it is because of hoped ease to learn and to implement both when both are same. Template argument is deduced from function call arguments. To function we can pass an array as argument but it will decay into pointer. We can take reference to array but then also in template we need to indicate that the parameter takes reference with that &. |
| Malcolm McLean <malcolm.arthur.mclean@gmail.com>: Jul 27 01:56AM -0700 On Tuesday, 26 July 2022 at 20:03:23 UTC+1, Keith Thompson wrote: > The C standard defines a "string" as "a contiguous sequence of > characters terminated by and including the first null character". > C has no string *type*, but it certainly does have strings. The C standard uses a lot of words in a special way. Like "function". "string" is another of those words. |
| "gdo...@gmail.com" <gdotone@gmail.com>: Jul 26 08:04PM -0700 every language where count begins at zero be fixed. puppy 0 puppy 1 puppy 2 ... please. this lends itself to off by one all over the place. pointers of yesterday to think of just one. lol, lol, lol i mean 0. lol |
| 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. |