- Elementary question on references. - 4 Updates
- Optional Code - a Better Way? - 2 Updates
- Elementary question on references. - 1 Update
- Struggling with bind syntax - 1 Update
- About virtual inheritance - 1 Update
pepstein5@gmail.com: Jul 07 08:02AM -0700 Textbooks often say things like "int& x = y; simply means that x is an alias for y." However, this is ambiguous (to me). Take the following case. std::vector<int> vec; /* ..... */ int index = 5; int& ref = vec[index]; Is ref an alias for vec[5] or for vec[index]? In other words if index changes from 5 to 6, does ref now refer to vec[6]? Or does ref always refer to vec[5]? Of course, I could just test it, but I would think there's a simple way of thinking about it that makes the answer apparent and unambiguous. It's clear to me that if we write int& i = index; int& clearRef = vec[i]; then surely clearRef always refers to vec[index] however index changes. But the previous case is unclear to me. Thank you very much for your help. Paul |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 07 06:19PM +0200 > Is ref an alias for vec[5] or for vec[index]? In other words if index > changes from 5 to 6, does ref now refer to vec[6]? Or does ref always refer > to vec[5]? Good question. In C++ a reference refers to the result of the evaluation of the initializer expression. But (as I recall) due to a sloppy formulation of the specification of an early version of the Algol language, it ended up with so called "call by name" where an argument expression effectively was substituted into the called routine at each place the formal argument name was used. It made for both interesting programming, interesting compiler techniques, and superb inefficiency. You can think of a C++ reference T& r = expr; as T* const _p = &expr; with a #define r (*_p) which explains most properties, except that since a macro definition doesn't respect scopes it can't really do the job. For more discussion based on that point of view see the FAQ items about references, at <url: https://isocpp.org/wiki/faq/references>. Where you need something akin to a reference to an expression, like an Algol call by name formal argument, you can use a named C++ lambda expression. vector<int> v; int i; auto const r = [&]() -> int& { return v[i]; } i = 42; r() = 12345; Cheers & hth., - Alf -- Using Thunderbird as Usenet client, Eternal September as NNTP server. |
"Öö Tiib" <ootiib@hot.ee>: Jul 07 10:16AM -0700 On Tuesday, 7 July 2015 18:03:41 UTC+3, peps...@gmail.com wrote: Alf already answered rest of it well enough. > Of course, I could just test it, but I would think there's a simple way of thinking > about it that makes the answer apparent and unambiguous. It is always worth testing when you think you understood something correctly. If you suspect that you did not understand it then the tests may also lie to you. Better ask or read it over from other textbook. For example you might want to be particularly careful with references to elements of vector since lot of operations that are done later with vector may invalidate references. Invalid references will often appear to work with existing C++ compilers. Somewhat safer is to use iterators to elements of vector. These tend to have debug versions that fail illegal usages with runtime errors instead of appearing to work. So if you test with such debug version then it is less likely to become mislead by test results. |
Vir Campestris <vir.campestris@invalid.invalid>: Jul 07 09:29PM +0100 On 07/07/2015 18:16, Öö Tiib wrote: > to elements of vector since lot of operations that are done later with > vector may invalidate references. Invalid references will often appear > to work with existing C++ compilers. They'll work up to the moment you are demonstrating your code to someone important. DAMHIK... And I don't expect that to change. Making all iterators fail, even if the memory is used for something else, is bound to be slow. > have debug versions that fail illegal usages with runtime errors instead > of appearing to work. So if you test with such debug version then it is > less likely to become mislead by test results. In my experience even the debug ones won't fail _all_ the illegal usages. But they do help a lot. Andy |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 07 06:42AM +0200 On 06-Jul-15 7:53 AM, Tobias Müller wrote: >> (Note: wProm & readStr are my functions.) Please advise. TIA > Stop writing spaghetti code, sparate the logic from the user interface. > Then write unittests that use fixed data to test the logic part. I second that. But I think that given the shown code, an example of getting into such mess, and out of it again, could be useful. For this example I'll use the following i/o support functions: ----------------------------------------------------------------------- <file "exception_util.hpp"> #pragma once #include <stdexcept> namespace my{ using std::runtime_error; using std::string; inline auto fail( string const& message ) -> bool { throw runtime_error( message ); } } // namespace my </file> ----------------------------------------------------------------------- <file "io_util.hpp"> #pragma once #include "exception_util.hpp" #include <iostream> #include <string> namespace my { using std::cin; using std::cout; using std::ostream; using std::getline; using std::string; inline auto int_from_user() -> int { string line; getline( cin, line ) || fail( "Input failed" ); return stoi( line ); } inline auto int_from_user( string const prompt ) -> int { cout << prompt; return int_from_user(); } class Output_value_list { private: ostream& stream_; bool is_first_value_; using This = Output_value_list; auto operator=( This const& ) -> This& = delete; public: template< class Value > void operator()( Value const& value ) { if( not is_first_value_ ) { stream_ << ", "; } stream_ << value; is_first_value_ = false; } Output_value_list( ostream& stream ) : stream_( stream ) , is_first_value_( true ) {} }; } // namespace my </file> *** STEP 0 We write a little program that outputs a mysterious (or not so very mysterious) sequence of numbers. The point is just to have a not completely trivial program to discuss and outfit with testing. ----------------------------------------------------------------------- <file "0/main.cpp"> #include "io_util.hpp" using my::int_from_user; using namespace std; auto main() -> int { int const ddx = int_from_user( "Delta? " ); int const n = int_from_user( "Number of numbers? " ); int x = 0; int dx = 0; for( int count = 1; count <= n; ++count ) { dx += ddx; x += dx; if( count > 1 ) { cout << ", "; } cout << x; } cout << endl; } </file> *** STEP 1 We choose the worst possible ways to add some unit testing to code, namely, we'll test generated text rather than the data itself, and we'll do this by sprinkling preprocessor directives all over the code in order to have just one source code file that's everything and that can be built as either the original program, or as a tester program: ----------------------------------------------------------------------- <file "1/main.cpp"> #include "io_util.hpp" using my::int_from_user; #include <assert.h> // assert #include <iostream> #include <stdexcept> // std::runtime_error #include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS #include <string> // std::string #include <sstream> // std::ostringstream; #include <utility> // std::begin, std::end using namespace std; #define IS_UNUSED( arg ) (void) arg; struct arg auto main( int n_args, char* args[] ) -> int { #ifdef TEST assert( n_args == 2 ); int const ddx = stoi( args[1] ); int const n = 7; ostringstream output; #else IS_UNUSED( n_args ); IS_UNUSED( args ); int const ddx = int_from_user( "Delta? " ); int const n = int_from_user( "Number of numbers? " ); ostream& output = cout;
Subscribe to:
Post Comments (Atom)
|
No comments:
Post a Comment