Hi, Aleksey! On Oct 23, Aleksey Midenkov wrote: > On Sun, Oct 22, 2017 at 10:27 PM, Sergei Golubchik <s...@mariadb.org> wrote: > >> 2. It is still passed as a pointer to functions. Why is that? > >> > >> The main feature of C++ references is that it cannot be NULL, so we > >> get segfault on top of the stack (closer to a cause), not the > >> bottom of it. I see that pointers are now widely used and mainly > >> assumed to be always non-NULL (i.e. dereferenced without > >> assertion). But placing such implicit contract on data is not > >> evident and bug-prone. IMHO it's much better to use references > >> whenever it is possible (and when there is no need in cosy NULL > >> semantic). What do you think? > > > > This is something that gets raised over and over. > > Some prefer C-style pointers over references, so that when you look at > > the function call: > > > > func(a,&b); > > > > you can immediately see that `a` is passed by value and cannot be > > modified by `func`, while `b` can. > > > > Others prefer C++ references. > > But are the reasons mentioned above not enough to once and for all > resolve the dilemma?
As we're talking about it (and were, many times) - apparently not :) > > I personally reside on the middle ground, where one uses pointers to > > pass "out" parameters, and const references for "in" parameters. > > > >> But for such lightweight structs like LEX_CSTRING it is even better > >> to pass by value, so we could have the conventience of type cast. > > > > What do you mean by that? > > #include <cstring> > > struct LEX_CSTRING > { > const char *str; > unsigned long length; > LEX_CSTRING() {} > LEX_CSTRING(const char *c_str) > { > str= c_str; > length= strlen(c_str); > } > }; > > void func(LEX_CSTRING arg) > { > }; > > class MyCunningString > { > public: > operator LEX_CSTRING() { return LEX_CSTRING(); } > }; > > int main() > { > MyCunningString str; > func(str); > const char* c_str; > func(c_str); > return 0; > } Okay. Looks good. > >> 3. LEX_CSTRING and LEX_STRING are now non-convertible. Why not to make: > >> > >> template <typename char_t> > >> struct st_mysql_lex_string > >> { > >> char_t *str; > >> size_t length; > >> }; > >> > >> typedef st_mysql_lex_string<char *> LEX_STRING; > >> typedef st_mysql_lex_string<const char *> LEX_CSTRING; > >> typedef st_mysql_lex_string<const unsigned char *> LEX_CUSTRING; > >> > >> ? > > > > What would that change? > > #include <cstring> > > template <typename char_t> > struct st_mysql_lex_string > { > char_t *str; > size_t length; > st_mysql_lex_string<char_t>(){} > template <typename charX_t> > st_mysql_lex_string<char_t>(st_mysql_lex_string<charX_t> &from) : > str ((char_t *) from.str), > length (from.length) {} > }; > > typedef st_mysql_lex_string<char *> LEX_STRING; > typedef st_mysql_lex_string<const char *> LEX_CSTRING; > typedef st_mysql_lex_string<const unsigned char *> LEX_CUSTRING; > > void func(LEX_CSTRING arg) > { > } > > int main() > { > LEX_STRING str; > func(str); > LEX_CUSTRING ustr; > func(ustr); > return 0; > } Right, so I thought. So template<> doesn't change anything. Constructors and passing-by value do. Anyway, type conversion is nice. It's rather annoying to cast between LEX_CSTRING and LEX_STRING, for example. Templates - not sure we could use them here, because these types sometimes need to work in pure C too. LEX_STRING does, at least. We could do, say struct LEX_STRING { char *str; size_t length; #ifdef __cplusplus LEX_STRING(...) { ... } #endif } to have some extra C++ convenience. But with templates you'd need a completely separate LEX_STRING definition in C and C++. Regards, Sergei Chief Architect MariaDB and secur...@mariadb.org _______________________________________________ Mailing list: https://launchpad.net/~maria-developers Post to : maria-developers@lists.launchpad.net Unsubscribe : https://launchpad.net/~maria-developers More help : https://help.launchpad.net/ListHelp