Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Error: lvalue required as unary ‘&’ operand. How to solve it?

116 views
Skip to first unread message

wyn...@gmail.com

unread,
Jun 6, 2018, 1:30:39 AM6/6/18
to
struct B {
B() {};
};

class AList {
B *m_ptr;
public:
AList() : m_ptr(0) {};
const B* ptr() const { return m_ptr; };
B* ptr() { return m_ptr; };
};

int main()
{
AList aa;
B** bpp=&aa.ptr(); // how to resolve this?

return 0;
};

$g++ test.cpp
test.cpp:16:18: error: lvalue required as unary ‘&’ operand
B** bpp=&aa.ptr();
^
----------

Bo Persson

unread,
Jun 6, 2018, 1:53:57 AM6/6/18
to
Why do you need this in the first place? Storing pointers to pointers is
not all that useful.

Anyway, the problem is that the ptr() call returns a temporary which
goes away at the ';'. Taking the address of something that immediately
goes away is not very useful.

If you must have a pointer to a pointer, you have to store the original
pointer first:

B* ptr = aa.ptr();
B** bpp = &ptr;


Bo Persson





Barry Schwarz

unread,
Jun 6, 2018, 2:07:30 AM6/6/18
to
On Tue, 5 Jun 2018 22:30:27 -0700 (PDT), wyn...@gmail.com wrote:

>struct B {
> B() {};
>};
>
>class AList {
> B *m_ptr;
> public:
> AList() : m_ptr(0) {};
> const B* ptr() const { return m_ptr; };
> B* ptr() { return m_ptr; };

Why do you have two versions of ptr()?

>};
>
>int main()
>{
> AList aa;
> B** bpp=&aa.ptr(); // how to resolve this?

ptr() returns a value, not an object. It makes no sense to evaluate
the address of a value. Think about
int p = &2;

If you want to store the address of the member m_ptr of a particular
object of type AList, you will need a member or friend function that
evaluates that address. Alternately, you could make m_ptr public and
then code
bpp = &aa.m_ptr;

The usual reason for a data member to be private is to prevent a user
from manipulating it except by provided interfaces. If bpp contains
the address of some m_ptr, then you have lost control of that object.
The usual approach is to have a get and a set member function that
will access the object for you (and perform the appropriate validity
checks).

> return 0;
>};
>
>$g++ test.cpp
>test.cpp:16:18: error: lvalue required as unary ‘&’ operand
> B** bpp=&aa.ptr();
> ^
>----------

--
Remove del for email

Fred.Zwarts

unread,
Jun 6, 2018, 3:22:40 AM6/6/18
to
schreef in bericht
news:b9872b81-a24e-4c06...@googlegroups.com...
Change
B* ptr() { return m_ptr; };
into
> B*& ptr() { return m_ptr; };

bpp will now receive the addres of m_ptr.

Whether it is wise to expose the address of a private member is another
question.

wyn...@gmail.com

unread,
Jun 6, 2018, 3:37:11 AM6/6/18
to
F.Zwarts於 2018年6月6日星期三 UTC+8下午3時22分40秒寫道:
Thanks. That works.

Fred.Zwarts

unread,
Jun 6, 2018, 4:44:52 AM6/6/18
to
"Barry Schwarz" schreef in bericht
news:sfuehd1rnj6c9q5ch...@4ax.com...
>
>On Tue, 5 Jun 2018 22:30:27 -0700 (PDT), wyn...@gmail.com wrote:
>
>>struct B {
>> B() {};
>>};
>>
>>class AList {
>> B *m_ptr;
>> public:
>> AList() : m_ptr(0) {};
>> const B* ptr() const { return m_ptr; };
>> B* ptr() { return m_ptr; };
>
>Why do you have two versions of ptr()?

These are different functions. Note the "const". One is used for const
objects, other for non-const objects.

const Alist Alconst;
const B * Bl = Alconst.ptr (); // Will use the const version.

Alist Al;
B* Cl = Al.ptr (); // Will use the non-const version.

James Kuyper

unread,
Jun 6, 2018, 7:02:30 AM6/6/18
to
Here's two alternative solutions. Whether either of these is suitable
depends upon the reason why you need bpp:

B** ptrptr() { return &m_ptr; }
...
B** bpp = aa.ptrptr();

Note that, functionally, this is equivalent to Fred Zwarts' suggestion.
Alternatively,

B* bp = aa.ptr();
B** bpp = &bp;

Alf P. Steinbach

unread,
Jun 6, 2018, 9:34:20 AM6/6/18
to
Eventually you'll advance to three star programmer level, and these
early problems will seem trivial.

<url: http://wiki.c2.com/?ThreeStarProgrammer>


Cheers!,

- Alf


wyn...@gmail.com

unread,
Jun 7, 2018, 12:14:13 AM6/7/18
to
Alf P. Steinbach於 2018年6月6日星期三 UTC+8下午9時34分20秒寫道:
Basically I use '()' and typedef to avoid such kind of ambiguity.

I have a templete class Wy_AtDestroy in my library.
https://sourceforge.net/projects/cscall/
It's written from eraly days since learning C++, not modified till
now, since I still have no idea how. Probably, a language specialist
as you are can shade some light.

Paavo Helde

unread,
Jun 7, 2018, 2:02:28 AM6/7/18
to
On 6.06.2018 16:34, Alf P. Steinbach wrote:
>
> Eventually you'll advance to three star programmer level, and these
> early problems will seem trivial.
>
> <url: http://wiki.c2.com/?ThreeStarProgrammer>

Three stars? Are you kidding? I have seen five stars in the code of a
coworker (who was desperately trying to figure out why his
five-times-nested loops were so slow).

Alf P. Steinbach

unread,
Jun 7, 2018, 7:30:50 AM6/7/18
to
It all depends on what the code is for, which is not evident.

E.g. if the pointer is meant to point to a dynamic size array, use
`std::vector`.


Cheers!,

- Alf


wyn...@gmail.com

unread,
Jun 7, 2018, 8:24:27 AM6/7/18
to
Alf P. Steinbach於 2018年6月7日星期四 UTC+8下午7時30分50秒寫道:
The question was from trying wrapping clib function getaddrinfo(2)
I changed my mind to use class (see CSCall/AddrInfo.h). As always,
nearly all the classes in the library expose what's wrapped,
explicitly violating C++ data encapsulation principle.

E.g. WyArray(std::vector), WyStr(std::string)

The fact past have been showing 'good'(not bad) to me, I don't
know why? Even we all admit data encapsulation is good!

Alf P. Steinbach

unread,
Jun 7, 2018, 4:49:38 PM6/7/18
to
Like this:

------------------------------------------------------------------------------
// Source encoding: utf-8
// MinGW g++ build: “g++ main.cpp -std=c++17 -lws2_32 -lntdll”

#include <stdlib/all/basics.hpp> //
https://github.com/alf-p-steinbach/Wrapped-stdlib
using namespace stdlib::ext::hopefully_and_fail; // hopefully, fail
using namespace stdlib::ext::type_builders; // ptr_, ref_

#include <winsock2.h>
#include <ws2tcpip.h> // getaddrinfo, inet_ntop

// Goal: to wrap
//
// int WSAAPI getaddrinfo(
// ptr_<char const> pNodeName,
// ptr_<char const> pServiceName,
// ptr_<const addrinfo> pHints,
// ptr_<ptr<addrinfo>> ppResult
// );

#if defined( __GNUC__ ) and not defined( NO_INET_NTOP_FIX )
inline auto inet_ntop(
const int family,
const ptr_<const in6_addr> address,
const ptr_<char> buffer,
const socklen_t buffer_size
)
{
assert( family == AF_INET6 ); (void) family;
assert( buffer_size >= INET6_ADDRSTRLEN ); (void) buffer_size;
RtlIpv6AddressToStringA( address, buffer );
return buffer;
}
#endif

namespace cppx
{
template< class Derived >
class Sequential_iteration
{
auto self() -> Derived& { return *static_cast<ptr_<Derived>>(
this ); }

public:
// void advance();
// friend auto equal( ref_<const D> a, ref_<const D> b ) -> bool;

auto operator++()
-> Derived&
{
self().advance();
return self();
}

auto operator++( int )
-> Derived
{
Derived original = self();
self().advance();
return original;
}

friend auto operator==( ref_<const Derived> a, ref_<const
Derived> b )
-> bool
{ return equal( a, b ); }

friend auto operator!=( ref_<const Derived> a, ref_<const
Derived> b )
-> bool
{ return not equal( a, b ); }
};
} // namespace cppx

namespace winsock
{
using std::size;
using std::string;
using std::to_string;

auto fail_with_code( const int code, ref_<const string> msg )
-> bool
{ return fail( msg + ", code " + to_string( code ) ); }

namespace address
{
inline auto raw_info_list(
ref_<const string> host, // E.g. "google.com",
decimal ip4, or hex ip6
ref_<const string> service // E.g. "http", or port
number
)
-> ptr_<addrinfo>
{
const addrinfo hints = {};
ptr_<addrinfo> p_first;
const int result = ::getaddrinfo(
host.c_str(),
service.c_str(),
&hints,
&p_first
);
hopefully( result == 0 ) or fail_with_code(
result, "winsock::address::raw_info_list - getaddrinfo
failed"
);
return p_first;
}

struct Family
{
enum Enum
{
unspecified = AF_UNSPEC, // 0 The address
Family is unspecified.
ip_v4 = AF_INET, // 2 Internet Protocol
version 4 (IPv4) address.
netbios = AF_NETBIOS, // 17 NetBIOS.
ip_v6 = AF_INET6, // 23 Internet Protocol
version 6 (IPv6).
irda = AF_IRDA, // 26 Infrared Data
Association (IrDA).
bluetooth = AF_BTH, // 32 Bluetooth.
};
};

class Info
{
::addrinfo* m_p_info;

public:
auto size() const
-> int
{ return m_p_info->ai_addrlen; }

auto family() const
-> Family::Enum
{ return static_cast<Family::Enum>( m_p_info->ai_family ); }

auto generic() const
-> ref_<const ::sockaddr>
{
assert( size() >= sizeof( ::sockaddr ) );
return *m_p_info->ai_addr;
}

auto is_ip_v4() const
-> bool
{
return
family() == Family::ip_v4
and size() >= sizeof( ::sockaddr_in );
}

auto unchecked_ip_v4_ptr() const
-> ptr_<const ::sockaddr_in>
{ return reinterpret_cast<ptr_<const ::sockaddr_in>>(
m_p_info->ai_addr ); }

auto ip_v4() const
-> ref_<const ::sockaddr_in>
{
assert( is_ip_v4() );
return *unchecked_ip_v4_ptr();
}

auto is_ip_v6() const
-> bool
{
return
family() == Family::ip_v6
and size() >= sizeof( ::sockaddr_in6 );
}

auto unchecked_ip_v6_ptr() const
-> ptr_<const ::sockaddr_in6>
{ return reinterpret_cast<ptr_<const ::sockaddr_in6>>(
m_p_info->ai_addr ); }

auto ip_v6() const
-> ref_<const sockaddr_in6>
{
assert( is_ip_v6() );
return *unchecked_ip_v6_ptr();
}

Info( const ptr_<::addrinfo> p_info )
: m_p_info{ p_info }
{}
};

class Info_list
{
ptr_<::addrinfo> m_p_first;
bool m_do_cleanup;

public:
class Iterator;

inline auto begin() const -> Iterator;
inline auto end() const -> Iterator;

~Info_list()
{
if( m_do_cleanup )
{
::freeaddrinfo( m_p_first );
}
}

explicit Info_list(
const ptr_<::addrinfo> p_first,
const bool do_cleanup = true
)
: m_p_first{ p_first }
, m_do_cleanup{ do_cleanup }
{}

Info_list(
ref_<const string> host,
ref_<const string> protocol = "http"
)
: Info_list{ raw_info_list( host, protocol ) }
{}
};

class Info_list::Iterator
: public cppx::Sequential_iteration<Iterator>
{
ptr_<addrinfo> m_p_current;

public:
void advance()
{
if( m_p_current )
{
m_p_current = m_p_current->ai_next;
}
}

friend auto equal( ref_<const Iterator> a, ref_<const
Iterator> b )
-> bool
{ return a.m_p_current == b.m_p_current; }

auto operator*() const
-> Info
{ return Info{ m_p_current }; }

Iterator( const ptr_<addrinfo> p_first = nullptr )
: m_p_current{ p_first }
{}
};

inline auto Info_list::begin() const
-> Iterator
{ return Iterator{ m_p_first }; }

inline auto Info_list::end() const
-> Iterator
{ return Iterator{ nullptr }; }
} // namespace address

inline auto string_from( ref_<const ::in_addr> address )
-> string
{ return ::inet_ntoa( address ); }

inline auto string_from( ref_<const ::in6_addr> address )
-> string
{
char buffer[INET6_ADDRSTRLEN];
return inet_ntop( address::Family::ip_v6, &address, buffer,
size( buffer ) );
}

class Library_envelope
{
WSAData m_info;

public:
auto major_version() const -> int { return
m_info.wHighVersion & 0xFF; }
auto minor_version() const -> int { return
m_info.wHighVersion >> 8; }
auto description() const -> string { return
m_info.szDescription; }

~Library_envelope() { WSACleanup(); }

Library_envelope()
{
const uint16_t major_version = 2;
const uint16_t minor_version = 2;
const uint16_t version = (minor_version << 8) | major_version;

const int result = WSAStartup( version, &m_info );
hopefully( result == 0 )
or winsock::fail_with_code(
result, "lib::Winsock::<init> - WSAStartup failed"
);
}
};
} // namespace winsock

namespace library
{
using Winsock = winsock::Library_envelope;
} // namespace library

namespace app
{
using namespace std;

auto operator<<( ref_<ostream> stream, ref_<const ::in_addr> address )
-> ref_<ostream>
{ return stream << winsock::string_from( address ); }

auto operator<<( ref_<ostream> stream, ref_<const ::in6_addr> address )
-> ref_<ostream>
{ return stream << winsock::string_from( address ); }

void run()
{
const library::Winsock ws;

cout << "Winsock " << ws.major_version() << "." <<
ws.minor_version() << "." << endl;
cout << "Its self-description: “" << ws.description() << "”."
<< endl;
cout << string( 72, '-' ) << endl;

auto const& hostname = "google.com";
winsock::address::Info_list info_list{ hostname };
cout << "Address information for host “" << hostname << "”:" <<
endl;
int i = 0;
for( const winsock::address::Info& info : info_list )
{
cout << endl;
cout << ++i << ": " << info.size() << " bytes." << endl;
switch( info.family() )
{
case winsock::address::Family::ip_v4:
{
ref_<const sockaddr_in> a = info.ip_v4();
cout << "Socket IP v4: "
<< "family " << a.sin_family
<< ", port " << a.sin_port
<< ", addr " << a.sin_addr
<< endl;
break;
}
case winsock::address::Family::ip_v6:
{
ref_<const sockaddr_in6> a = info.ip_v6();
cout << "Socket IP v6: "
<< "family " << a.sin6_family
<< ", port " << a.sin6_port
<< ", flowinfo " << a.sin6_flowinfo
<< ", addr " << a.sin6_addr
<< ", scope_id " << a.sin6_scope_id
<< endl;
break;
}
default:
{
cout << "Socket in family " << info.family() << "."
<< endl;
break;
}
}
}
}
} // namespace app

auto main()
-> int
{
using namespace std;
try
{
app::run();
return EXIT_SUCCESS;
}
catch( exception const& x )
{
cerr << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
------------------------------------------------------------------------------


> I changed my mind to use class (see CSCall/AddrInfo.h). As always,
> nearly all the classes in the library expose what's wrapped,
> explicitly violating C++ data encapsulation principle.
>
> E.g. WyArray(std::vector), WyStr(std::string)
>
> The fact past have been showing 'good'(not bad) to me, I don't
> know why? Even we all admit data encapsulation is good!


Cheers!,

- Alf

wyn...@gmail.com

unread,
Jun 7, 2018, 11:50:18 PM6/7/18
to
Alf P. Steinbach於 2018年6月8日星期五 UTC+8上午4時49分38秒寫道:
0. 1st, I don't know window stuff, can't compile and test (this code
seems to be your implements), and the newer C++ key word auto and
syntax, the trailing "->int" seems to be a hint of the type of auto
So, try to understand as I can

1. catch( exception const& x ) {
}; // older compiler has to end with ';'. I didn't try newer compilers

2. Quite some codes are dedicated for implementing iterator which I had
decided not to use (reason?...)

3. Quite some indirections: e.g. ptr_<char const>, ref_(const string)
probably that's something I should learn, but exposing it to public
interface is questionalbe to me, now. (probably fine, template
may encounter problems using POD pointer or reference plus const)

4. A basic goal of Wy::AddrInfo (the library in general) is to avoid
modification of the source wrapper from the underlying things that
can change over time

5. getaddrinfo(2) uses different set of return value and meaning.

6. In general, the implements you presented seemd to me incomplete for
all possible network protocols. With my implement, E.g.

const char node[]="groups.google.com";
const char service[]="https";
Wy::AddrInfo hints;
Wy::AddrInfoList alst;

hints.set_socktype(SOCK_STREAM);
hints.set_family(AF_UNSPEC);

// Get an AddrInfo entry list
// Because EAI_AGAIN can be returned, we use for(;;) loop
for(;;) {
WyEai v=alst.getaddrinfo(node,service,&hints);
if(v==0) {
break;
}
if(v==EAI_SYSTEM) {
WY_THROW( WyRet(errno) );
}
if(v==EAI_AGAIN) {
continue;
}
Wy::cerr << Wy::strerror(v) << WY_ENDL;
WY_RETURN( WyRet() );
}

// Try connect to all AddrInfo entries, protocol free, even AF_ATM,
// AF_X25,..., should be OK. User don't need to know about these
// things at the level
//
for(const Wy::AddrInfo *aiptr=alst.begin(); aiptr!=NULL;
aiptr=aiptr->next()) {
WySockAddrStorage aiaddr(aiptr->addr(),aiptr->addrlen());
WySockFile sock;
WyRet r;
if((r=sock.reset(aiptr->family(),
aiptr->socktype(),
aiptr->protocol())) !=Wy::Ok) {
Wy::cerr << Wy::wrd(r) << WY_ENDL;
continue;
}

// Connect to aiaddr
if((r=sock.connect(aiaddr))!=Wy::Ok) {
WY_HERE(); Wy::cerr << Wy::wrd(r) << WY_ENDL;
continue;
}
// ....
}

I was seeking for suggestions and idea. All the above are just my
thoughts of the moment, no criticism intended.

Jorgen Grahn

unread,
Jun 8, 2018, 1:37:25 AM6/8/18
to
On Thu, 2018-06-07, wyn...@gmail.com wrote:
...
>
> The question was from trying wrapping clib function getaddrinfo(2)

[To non-Unix people: getaddrinfo(2) is a name server lookup function
in POSIX.]

What's the goal of wrapping it? Looking at my code for a server, I have
a function like this, which uses getaddrinfo():

/* Create a listening socket on host:port (the wildcard address if
* host is empty). Does everything including listen(), and prints
* relevant error messages on stderr.
*/
int listening_socket(const std::string& host,
const std::string& port)
... (43 lines of code)

So it's already wrapped in application-specific code.

I used to believe in wrapping the POSIX API with C++ in a general way,
but I no longer see a big benefit.

getaddrinfo() is a good candidate for wrapping:
- It allocates memory which you must free.
- It creates a linked list of addresses which you have to traverse,
and hold on to for a while while you try using them.
- It's really several different functions merged into one (you call it
in one way if you want a client socket, another if you want a server
socket).
- ...

But why bother, when I already have listening_socket() above?

Client code may have slightly different needs.

Also compare with how Boost.Asio wraps getaddrinfo(). (I'm not sure I
like it 100%, though.)

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

wyn...@gmail.com

unread,
Jun 8, 2018, 3:58:37 AM6/8/18
to
Jorgen Grahn於 2018年6月8日星期五 UTC+8下午1時37分25秒寫道:
> On Thu, 2018-06-07, wyn...@gmail.com wrote:
> ...
> >
> > The question was from trying wrapping clib function getaddrinfo(2)
>
> [To non-Unix people: getaddrinfo(2) is a name server lookup function
> in POSIX.]
>
> What's the goal of wrapping it? Looking at my code for a server, I have
> a function like this, which uses getaddrinfo():
>

[Copy from CSCall++ project summary]
A C++ library genuinely for system programming by wrapping commonly
used system calls and C library functions into forms appropriate in
C++ context for system programming. The API is designed fool-proof,
application normally just use it mechanically, not many rule/names
invented to remember.

This C++ library wraps *many* clib/system call functions to form a
consistent C++ API, a thin layer of abstraction is needed so user
don't have to worry about changes of those wrapped functions.
(clib and system call functions do have changed a bit these years)

> /* Create a listening socket on host:port (the wildcard address if
> * host is empty). Does everything including listen(), and prints
> * relevant error messages on stderr.
> */
> int listening_socket(const std::string& host,
> const std::string& port)
> ... (43 lines of code)
>
> So it's already wrapped in application-specific code.
>

That's fine, except funtionality is limited.
There's are various socket options (see socket(2)) that can't be
determined by "host" and "port"

> I used to believe in wrapping the POSIX API with C++ in a general way,
> but I no longer see a big benefit.
>
> getaddrinfo() is a good candidate for wrapping:
> - It allocates memory which you must free.
> - It creates a linked list of addresses which you have to traverse,
> and hold on to for a while while you try using them.
> - It's really several different functions merged into one (you call it
> in one way if you want a client socket, another if you want a server
> socket).
> - ...
>
> But why bother, when I already have listening_socket() above?
>
> Client code may have slightly different needs.
>

I'm sure you are not familiar with clib/system calls. The word 'wrap'
sounds easy, but there are many subtle details and macros to use
them, (except getaddrinfo, and this library also has to consider
thread-safe, signal-safe issues... In all, implimentation is not
trival as you thought.

> Also compare with how Boost.Asio wraps getaddrinfo(). (I'm not sure I
> like it 100%, though.)
>
> /Jorgen
>
> --
> // Jorgen Grahn <grahn@ Oo o. . .
> \X/ snipabacken.se> O o .

This question is equ. to ask why Boost.Asio wraps getaddrinfo()
( you may also need 100% not like it to say so )

This library has a different feature about 'socket' you may like it.
All the 'files' of this library (regular file, character special file,
socket, fifo) are derived from WyByteFlow, same for Wy::cin/Wy::cout
/Wy::cerr. So:

1. Wy.cout.reset(socket) // cout is now a socket file
Wy.cin.reset(fifo) // cin is now a fifo or a pipe

2. operator <<, operator >> work for all WyByteFlow instances, so you
can type:

socket << "asdf" WY_ENDL;

Jorgen Grahn

unread,
Jun 8, 2018, 3:26:23 PM6/8/18
to
On Fri, 2018-06-08, wyn...@gmail.com wrote:
> Jorgen Grahn於 2018年6月8日星期五 UTC+8下午1時37分25秒寫道:
...
>> /* Create a listening socket on host:port (the wildcard address if
>> * host is empty). Does everything including listen(), and prints
>> * relevant error messages on stderr.
>> */
>> int listening_socket(const std::string& host,
>> const std::string& port)
>> ... (43 lines of code)
>>
>> So it's already wrapped in application-specific code.
>
> That's fine, except funtionality is limited.
> There's are various socket options (see socket(2)) that can't be
> determined by "host" and "port"

Yes -- that's why I called listening_socket() application-specific.
It sets SO_REUSEADDR and the sizes of socket buffers, chooses TCP
and so on. It would look different in another program.

Öö Tiib

unread,
Jun 8, 2018, 6:18:42 PM6/8/18
to
On Friday, 8 June 2018 08:37:25 UTC+3, Jorgen Grahn wrote:
> Also compare with how Boost.Asio wraps getaddrinfo(). (I'm not sure I
> like it 100%, though.)

When we like something 80% then it is probably quite good. ;)

Jorgen Grahn

unread,
Jun 9, 2018, 3:39:40 AM6/9/18
to
I had roughly this problem with it in one project: there are socket
options you must set after creating the socket, but before connect()
(I needed TCP connect() to give up early, not after a minute or more
of attempts). The async API for this bundled everything from
getaddrinfo() to connect(), with no hooks for me to set the options,
so I had to reimplement much of it.

That left me with the feeling that that particular part of the API
hadn't been used much for serious work. (They may have fixed that by
now though; this was ~2 years ago.)

Öö Tiib

unread,
Jun 9, 2018, 9:22:51 AM6/9/18
to
I have worked with it rarely but it feels to me pretty straightforward.
So we can have asio socket:

asio::ip::tcp::socket the_socket;

Then we can call things like the_socket.open() or the_socket.bind() and
the like. To get native socket there is method native().

SOCKET n_socket = the_socket.native();

With it can be done platform-specific things like option changes before
connect():

int result = SOCKET_ERROR;
if (INVALID_SOCKET != n_socket)
{
result = ::setsockopt(n_socket, SOL_SOCKET, blah blah SO_RCVTIMEO);
}

If there are multiple platforms to support then such function can be
moved to platform-specific unit and linked in depending on platform.
Sure, if it was couple of years back then you do not remember the
details, but to me it seemed OK more or less. So at least 80% "like"
from me. ;)


Alf P. Steinbach

unread,
Jun 9, 2018, 1:10:51 PM6/9/18
to
On 08.06.2018 05:50, wyn...@gmail.com wrote:
> Alf P. Steinbach於 2018年6月8日星期五 UTC+8上午4時49分38秒寫道:
>> [snip code]
>
> 0. 1st, I don't know window stuff, can't compile and test (this code
> seems to be your implements),

Ideally you just need to replace Winsock2 headers with your system's
sockets implementation, and re-implement the little Library_envelope
class that initializes and cleans up Winsock2, for your implementation.

Disclaimer: I haven't tried it.


> and the newer C++ key word auto and
> syntax, the trailing "->int" seems to be a hint of the type of auto
> So, try to understand as I can

There's not much to understand, it's just notation that for this code
maps directly (mechanically, one to one) to C++03 notation. The modern
C++ notation is much like Rust and like math notation. But I don't think
either notation has any strong advantage for this particular concrete code.


> 1. catch( exception const& x ) {
> }; // older compiler has to end with ';'. I didn't try newer compilers

A semicolon there has never been a requirement in standard C++, and as I
recall not in ARM C++ before the first standard, either.

Throw that compiler on the fire.


> 2. Quite some codes are dedicated for implementing iterator which I had
> decided not to use (reason?...)

You can directly reuse that code (perhaps more properly beefed up for
reuse), by just moving it to a header.

I put everything in a single file so that it would be easy to check out.


> 3. Quite some indirections: e.g. ptr_<char const>, ref_(const string)
> probably that's something I should learn, but exposing it to public
> interface is questionalbe to me, now. (probably fine, template
> may encounter problems using POD pointer or reference plus const)

In my view, `ptr_<T>` is more direct and readable than `T*`. The latter
can be more easily recognized, yes, but leads to undecipherable
declarations like those for signal handlers, and needs to be learned.

Re the “needs to be learned” of stars: I first encountered the star
notation in SPL on the HP3000. I didn't understand it then. Now I'm
pretty sure it must have been just about the same as in C.

If instead the SPL notation had been ptr_, or like that, then I would
most likely have understood it because it's self-describing.


> 4. A basic goal of Wy::AddrInfo (the library in general) is to avoid
> modification of the source wrapper from the underlying things that
> can change over time

Sorry, I don't understand that. Can you give an example?


> 5. getaddrinfo(2) uses different set of return value and meaning.

Sorry, I don't understand that either.

The docs I found for *nix systems:
<url: https://linux.die.net/man/3/getaddrinfo>

Are you referring to a different function?


> 6. In general, the implements you presented seemd to me incomplete for
> all possible network protocols. With my implement, E.g.
>
> const char node[]="groups.google.com";
> const char service[]="https";
> Wy::AddrInfo hints;
> Wy::AddrInfoList alst;
>
> hints.set_socktype(SOCK_STREAM);
> hints.set_family(AF_UNSPEC);

I don't see any problem with providing the hinting functionality, that's
just adding an argument.


> [snip more code]
> I was seeking for suggestions and idea. All the above are just my
> thoughts of the moment, no criticism intended.

Communication is IMHO good. That's what Usenet groups and now to some
degree Reddit, are about. With communication we can learn, and we can
get corrected, and we can get an idea of what other folks think.

Generally, on Usenet and to a large degree still on Reddit, you're
expected to provide feedback and generally say what you mean and provide
what facts you know, which is a positive thing.

On Reddit some users (kids? manipulative?) will downvote any corrective
communication as perceived negativity, maybe like ooh you're not
friendly-friendly, go away. On Stack Overflow which is even more of a
social site that [correction or disagreement = negative social signal]
reaction is the norm, plus the SO mods are likely to remove critical
context from the comment flow, and some times, though rarely, even from
the comments themselves, plus you can't in general back up your comments
with code examples because you can't have formatted code in SO comments.
Plus there's not a comment hierarchy, just linear. Plus no support for
quoting in comments. And so on; it's designed to stifle any debate. Plus
you can be suspended for mentioning competence. I think that's my
current situation, a comment about please don't use mod tools until
competent to do so, but the mods are very tight-lipped about it except
that in their view I've been more “rude” again. Happily there's no need
to assume the silly SO authoritarianism and herd behavior on Usenet.


Cheers!,

- Alf

wyn...@gmail.com

unread,
Jun 10, 2018, 5:15:22 AM6/10/18
to
Alf P. Steinbach於 2018年6月10日星期日 UTC+8上午1時10分51秒寫道:
> On 08.06.2018 05:50, wyn...@gmail.com wrote:
> > Alf P. Steinbach於 2018年6月8日星期五 UTC+8上午4時49分38秒寫道:
> >> [snip code]
> >
> > 0. 1st, I don't know window stuff, can't compile and test (this code
> > seems to be your implements),
>
> Ideally you just need to replace Winsock2 headers with your system's
> sockets implementation, and re-implement the little Library_envelope
> class that initializes and cleans up Winsock2, for your implementation.
>
> Disclaimer: I haven't tried it.
>
>
> > and the newer C++ key word auto and
> > syntax, the trailing "->int" seems to be a hint of the type of auto
> > So, try to understand as I can
>
> There's not much to understand, it's just notation that for this code
> maps directly (mechanically, one to one) to C++03 notation. The modern
> C++ notation is much like Rust and like math notation. But I don't think
> either notation has any strong advantage for this particular concrete code.
>

I take it as suggestions to use keyword auto this way (in the future)

I do not know many new C++ things. But when I need them, they will come
to me naturally.

>
> > 1. catch( exception const& x ) {
> > }; // older compiler has to end with ';'. I didn't try newer compilers
>
> A semicolon there has never been a requirement in standard C++, and as I
> recall not in ARM C++ before the first standard, either.
>
> Throw that compiler on the fire.
>

g++ had once interpreted the C++ standard's wording 'straitforwardly'.
The DOS time Turbo/Watcom C++, IIRC might had been slightly different.
E.g.

void test_throw()
{
try {
throw char(4);
}
catch(int e) {
cout << "caught int(4)";
}

try {
throw char(3);
}
catch(char e) {
cout << "caught char(3)";
}
}

That older g++ would caught the 1st 'throw char(4)' in the 2nd
catch(char e) if without the ending ';'.
I tried newer g++'s, program behaviors as average users expected, now.

Probably I should say 'earlier', because C++ compliler implements
had once debated about the ending ';' issues, e.g. the following
class declaration might had once worked.

class B {
void a(int);
void b(char) {}
}

>
> > 2. Quite some codes are dedicated for implementing iterator which I had
> > decided not to use (reason?...)
>
> You can directly reuse that code (perhaps more properly beefed up for
> reuse), by just moving it to a header.
>
> I put everything in a single file so that it would be easy to check out.
>

OK. when I see fit.

>
> > 3. Quite some indirections: e.g. ptr_<char const>, ref_(const string)
> > probably that's something I should learn, but exposing it to public
> > interface is questionalbe to me, now. (probably fine, template
> > may encounter problems using POD pointer or reference plus const)
>
> In my view, `ptr_<T>` is more direct and readable than `T*`. The latter
> can be more easily recognized, yes, but leads to undecipherable
> declarations like those for signal handlers, and needs to be learned.
>
> Re the “needs to be learned” of stars: I first encountered the star
> notation in SPL on the HP3000. I didn't understand it then. Now I'm
> pretty sure it must have been just about the same as in C.
>
> If instead the SPL notation had been ptr_, or like that, then I would
> most likely have understood it because it's self-describing.
>

This reminded me of several other similar programming practices:
E.g 'const char' or 'char const'
'if(a==0)' or 'if(0==a)'
...

Most difficult coding styles taking time to decipher I encountered
were from people just graduate from school, they didn't want people to
share their 'know-how' or just show off (newer C++ syntax provides more
such chances)

>
> > 4. A basic goal of Wy::AddrInfo (the library in general) is to avoid
> > modification of the source wrapper from the underlying things that
> > can change over time
>
> Sorry, I don't understand that. Can you give an example?
>

That basic goal is an ideal to pursue. It basically means the impl.
better not to add other things. So the changes of wrapped underlying
functions can be transparent/intact. E.g. various C++ implements are
always tempted to add things ('policy'...) to look like 'real C++',
that might lead to the need to update the C++ wrappers. I'd like to
save such time, I have something else as important to do.

getaddrinfo(2) looks stable and thread safe, but who knows? Latter
version might expose more details of struct addrinfo or add 'flags' to
the argument of getaddrinfo(..) like some others do. For this,
thanks to a C++ feature, we can add default argument in response.

>
> > 5. getaddrinfo(2) uses different set of return value and meaning.
>
> Sorry, I don't understand that either.
>
> The docs I found for *nix systems:
> <url: https://linux.die.net/man/3/getaddrinfo>
>
> Are you referring to a different function?
>

I meant the return code of getaddrinfo(2). I can't read it from your
post. It's different from errno. There are couple of clib functions
use different return code, too. Because it is a big thing to look for,
i.e. 'error handling mechnism', the big picture.
I know you know this had been a long long thing ever discussed.
In libwy-0.55, I decided to give up the original design to use errno
directly (wrapped by WyRet).

>
> > 6. In general, the implements you presented seemd to me incomplete for
> > all possible network protocols. With my implement, E.g.
> >
> > const char node[]="groups.google.com";
> > const char service[]="https";
> > Wy::AddrInfo hints;
> > Wy::AddrInfoList alst;
> >
> > hints.set_socktype(SOCK_STREAM);
> > hints.set_family(AF_UNSPEC);
>
> I don't see any problem with providing the hinting functionality, that's
> just adding an argument.
>

So the argument is a pointer type, but still, that means using default
settings
Sorry, I don't understand 'Reddit' and 'SO mode'. From what I can perceieve
,Stack Overflow is a commercial website like Yahoo, the heart is money.
Users, these year, have been showing some kind of ...ism emerging, or
redefinition of the so called democrocy communism fascism socialism terrorism,..., are just begun.
0 new messages