Sorry for somewhat misordering the discussion. I simply didn't see post #8 until now, and I don't know how I missed it.
I was really just using it for control-flow, but if I do ever decide to throw exceptions from the library that would be the way to go, yes.
O_o
You are just using `failure' as cleanup option because you haven't put everything into a component that can successfully cleanup/rollback its own self.
Placing such primitives into such components is really what I was suggesting.
Except that allowing the user to supply their own string type is complicated by the fact that the POSIX functions expect canonical C-strings.
Except that the use of `std::string' I'm referring to is limited to lookup/reverse lookup related to addresses.
[Edit]
You have some convenience overloads doing conversion, but I'm not interested in those as the conversion layer is ultimately implemented by the client.
[/Edit]
Yes, you'll have more work to do; doing it properly by hiding the conversion is the same thing you are doing at other points in the code, and that work simplifies the look and feel of the code.
Code:
wchar_t * s(ReadIPFromUser());
socket /* whatever */ host(ConvertToANSII(s));
/* have a socket */
Code:
char * s(ReadIPFromUser());
socket /* whatever */ host(s);
/* have a socket */
The examples aren't really bad.
I'm not saying they are bad.
I'm just saying that they could be better with not all that much work.
Code:
socket /* whatever */ host(ReadIPFromUser());
/* have a socket */
The data could be ASCII or UTF-8 or any other format you wish to support.
If you don't wish to support anything other than ASCII, you could still provide a "hook"--`ConvertUserIPToASCII' for example--called by the templated constructor to allow clients to transparently extend to the support.
You mean a runtime error check rather than one performed at compile-time, or what?
No. I am definitely not talking about an error triggered during program execution.
I am talking about a "firewall" to prevent copying during compile.
As is, attempting to copy certain objects will force the compiler to complain--somewhat ambiguously for most--about no valid constructor for `managed_socket' despite the fact that the `managed_socket' doesn't appear in the related client code.
I'm talking about forcing the compiler to make a specific complaint where possible, such as "client objects can not be copied", by conditionally--similarly to the `ITSA_WINSOCK_PLATFORM' configuration macro--using `static_assert'.
There's nothing wrong with returning boolean values provided that the operations are "atomic" enough.
I didn't say there was anything wrong with return codes. You are thinking about some other member of this forum.
I said converting back and forth is an "anti-pattern", and I am completely correct.
Everywhere you've made those paired conversion could be simplified and implemented without redundancy or falling to the "anti-pattern" with a few helper functions and a few more primitives that "know how to rollback".
I'd recommend just throwing something useful to the client, but you could definitely use a return value instead.
Plus forcing users to catch exceptions can make *their* code less manageable as a result.
That could actually be the case, but you trap an exception locally calling `shutdown'/`reset'/similar for these error conditions.
You don't have to put the object into such a state, but you are putting the object into such a state.
A client can't benefit from return codes--as opposed to exceptions--as easily as you imply.
I, as a client, must check the return value at every point or risk using a silently invalidated object most likely losing valuable error information in the process.
Code:
if(server.recv(/*...*))
{
if(client.send(/*...*))
{
if(server.recv(/*...*))
{
}
}
}
(Obviously, that approach is atrocious so more likely I would wrap the conditions into a fail bit as you've internally done.)
I could just use the object as you've suggested, but I would no way of knowing where an error occurred unless I "watched" for the failure as above.
If you want to allow for that sort of pattern, you still have more work. You need to provide some sort of stable error code which I can query.
The internal error code, as currently implemented, is not sufficient. You do not religiously check validity before using underlying components which will result in the underlying error code being updated on many platforms.
If you make the suggested change by providing a stable error code, you would be allowing for late error propegation/discovery.
You are correct in saying that some styles of coding benefit from the approach, but I agree with Elysia. I find late discovery to be a waste of time in any language, and I certainly see no reason to try for it in C++.
I suppose I could just assume std::bad_alloc has been thrown in such an event and use some sort of back-off scheme to mitigate OOM situations.
You already assume quite a lot about the buffer; I see no reason that one more assumption should cause anyone problems the other assumptions would not already imply.
Good idea, but just keep in mind that since the data can't be assumed to be contiguous so those reads/writes are going run a bit slower.
Obviously. I'm talking about a convenience layer.
You should document the potential for slower throughput.
Otherwise, I don't see any issue; you said yourself, after a fashion, that you aren't responsible for yahoos not reading the documentation.
Soma