Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Jan posted:

The compiler most likely optimises the empty constructor call anyway. You're mostly losing terseness and clarity for... no advantage at all.

Now if the destructor was virtual, you'd have a bit more reason to leave an empty base one, but this is not the case.
Note that if the destructor was virtual the compiler most likely wouldn't optimise the empty destructor call away.

Adbot
ADBOT LOVES YOU

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Dooey posted:

Removing the dustructor doesn't change my performance problems :(

I did say that it wouldn't. About that: your profiler is almost certainly misleading you; line-based profilers are often not terribly precise, because optimization can do terrible things to line tables. You *are* profiling an optimized build, right?

I would suggest looking at the assembly and seeing if there's anything fishy going on.

Dooey posted:

Does having an empty destructor like that actually change anything relative to leaving out the destructor?

Yes. Classes with non-trivial copy constructors or non-trivial destructors must be passed and returned indirectly, i.e. by passing a pointer to a temporary. User-declared destructors are automatically non-trivial (*), even if they're defined empty inside the class definition. So passing a Point<float> to a function means always passing it in memory instead of potentially in registers.

(*) Note to C++0x pedants: shut up.

schnarf
Jun 1, 2002
I WIN.

Dooey posted:

The constructors and destructors for Point:

code:
template<typename T> Point<T>::Point() {
}

template<typename T> Point<T>::Point(T newX, T newY) {
    x = newX;
    y = newY;
}

template<typename T> Point<T>::~Point() {
}
and the whole thing: http://codepad.org/a9Gvyb8s

Also I'm trying not to fall into any bad practices with this project, so if you see anything stupid or smelly that I'm doing, please tell me :)
It's just a small thing, but you should use an initializer list in the constructor. In this case it probably makes no difference, but in general doing it your way could cause the compiler to first default construct the member variables, and then reassign them.
code:
template <typename T> Point<T>::Point(T newX, T newY) :
    x(newX),
    y(newY) {
}

MrMoo
Sep 14, 2000

C99 to C++, what is the best way to convert strict aliasing safe casting?

Common code
code:
struct gsi_t {
        uint8_t b[6];
};

struct tsi_t {
        gsi_t gsi;
        uint16_t s;
}
C99 code that performs simple comparison, taking pointers
code:
bool
tsi_equal (
	const void* restrict p1,
	const void* restrict p2
        )
{
	const union {
		tsi_t		tsi;
		uint32_t	l[2];
	} *restrict u1 = p1, *restrict u2 = p2;

	return (u1->l[0] == u2->l[0] && u1->l[1] == u2->l[1]);
}
C++ code to perform less than comparison, taking references
code:
bool tsi_less (const tsi_t &ltsi, const tsi_t &rtsi)
{
#if 0
        uint32_t lu[2], ru[2];
        memcpy (lu, &ltsi, sizeof(lu));
        memcpy (ru, &rtsi, sizeof(ru));
#else
        const union {
                tsi_t ltsi_;
                uint32_t lu[2];
        };
        const union {
                tsi_t rtsi_;
                uint32_t ru[2];
        };
        ltsi_ = ltsi;
        rtsi_ = rtsi;
#endif
        return (lu[0] < ru[0]) || (lu[0] == ru[0] && lu[1] < ru[1]);
}
memcpy or unions, or is there a method using reinterpret_cast? This is deliberately avoiding lexicographical_compare.

MrMoo fucked around with this message at 04:37 on Sep 16, 2010

MrMoo
Sep 14, 2000

Similar question on stack overflow, http://stackoverflow.com/questions/346622/opinions-on-type-punning-in-c

Looks like these are the only two strict aliasing safe options, the memcpy is shorter and may be optimised out in GCC as it does in C99 usage.

epswing
Nov 4, 2003

Soiled Meat
Hoo boy. Learning C++.

:negative:

I'm trying to create a Named Pipe

Going off some examples, I'm doing something like

code:
string x = "\\\\.\\pipe\\MyPipeName";
CreateNamedPipe(x.c_str(), blah, blah, blah, ...)
and VS2010 is telling me

quote:

argument of type "const char *" is incompatible with parameter of type "LPCWSTR"

1) Why the discrepancy between the docs saying I need a LPCTSTR, and VS2010 saying I need a LPCWSTR?

2) Do I seriously need an 11-line function to convert from a std:string to a std::wstring so I can do mywstring.c_str()?

litghost
May 26, 2004
Builder

epswing posted:

Hoo boy. Learning C++.

:negative:

I'm trying to create a Named Pipe

Going off some examples, I'm doing something like

code:
string x = "\\\\.\\pipe\\MyPipeName";
CreateNamedPipe(x.c_str(), blah, blah, blah, ...)
and VS2010 is telling me


1) Why the discrepancy between the docs saying I need a LPCTSTR, and VS2010 saying I need a LPCWSTR?

2) Do I seriously need an 11-line function to convert from a std:string to a std::wstring so I can do mywstring.c_str()?

1) The key difference between LPCTSTR and LPCWSTR is the W, meaning wide char (short * vs char *), because it is encoded in UCS-16 I believe. The simplest solution is to actually switch to the ASCII versions of the API. Unless you really need unicode, then you just need to suffer.

You simply need to not define UNICODE before you include windows.h, i.e.

code:
#undef UNICODE
#include <Windows.h>
Or you can remove the UNICODE define from your build system.

litghost fucked around with this message at 16:42 on Sep 16, 2010

epswing
Nov 4, 2003

Soiled Meat
Thanks litghost. Where should I be doing #undef UNICODE?

Does this have anything to do with anything?

quote:

#error directive: Please use the /MD switch for _AFXDLL builds c:\program files (x86)\microsoft visual studio 10.0\vc\atlmfc\include\afxver_.h 81 3

Also when I hover over CreateNamedPipe in my project I see #define CreateNamedPipe CreateNamedPipeW, and when I hover over the project I'm using as an example, I see #define CreateNamedPipe CreateNamedPipeA. What's the difference, and should I care?

O_Kafetzis
Feb 15, 2010

by Nyc_Tattoo

epswing posted:

Also when I hover over CreateNamedPipe in my project I see #define CreateNamedPipe CreateNamedPipeW, and when I hover over the project I'm using as an example, I see #define CreateNamedPipe CreateNamedPipeA. What's the difference, and should I care?
CreateNamedPipeA takes a char* and CreateNamedPipeW takes a wchar*. You want CreateNamedPipeA if you are calling c_str().

litghost
May 26, 2004
Builder

epswing posted:

Does this have anything to do with anything?

That is a different problem. You need to select the Multithreaded DLL runtime when building against AFX, or at least that is what I glean from the error message (/MD is the flag for the Multithreaded DLL runtime). Make sure the /MD flag is present in your compiler flags.

epswing posted:

Also when I hover over CreateNamedPipe in my project I see #define CreateNamedPipe CreateNamedPipeW, and when I hover over the project I'm using as an example, I see #define CreateNamedPipe CreateNamedPipeA. What's the difference, and should I care?

The above poster is correct, but behind the scenes is the following code:
code:
#ifdef UNICODE
#define CreateNamedPipe CreateNamedPipeW
#else
#define CreateNamedPipe CreateNamedPipeA
#endif
That definition exists for all Win API functions that take strings. If you are using more than one API call, it maybe simpler to just remove the UNICODE define.

litghost fucked around with this message at 17:42 on Sep 16, 2010

epswing
Nov 4, 2003

Soiled Meat
Ok, I'm on board, but where should I be doing #undef UNICODE?

If I put it at the top of the cpp file which contains CWinApp theApp; (which I assume to be the entry point of the app), or at the top of stdafx.h, I still get

quote:

Error 1 error C2664: 'CreateNamedPipeW' : cannot convert parameter 1 from 'const char *' to 'LPCWSTR'

e: I'd like to know how to figure out which file I need to edit, just as much as I'd like to know which file I need to edit.

epswing fucked around with this message at 17:59 on Sep 16, 2010

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Before you go the route of unnecessarily stripping unicode support from your app, this code should work:

code:
wstring x = L"\\\\.\\pipe\\MyPipeName";
CreateNamedPipe(x.c_str(), blah, blah, blah, ...)

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
I love you, RJ.

Also, I typically recommend just using the W versions instead of those dumb macros.

epswing
Nov 4, 2003

Soiled Meat
I'm on the fence about just Getting Things Working followed by worrying about unicode support, versus trying to get over the hump of trying to make unicode work from the get-go.

I'd like to try the latter, but it might take too long for me to understand how to do things properly. For example, to create my pipe, now the constructor takes a wstring instead of a string, so when I create the object now it's something like pipe(L"MyPipeName"). Easy enough, but now this means to concat two strings, I can't just do "one" + "two", it needs to be

code:
wstring Pipe::GetPipeName()
{
	wstring name = L"\\\\.\\pipe\\";
	name += this->pipeName;
	return name;
}
Ok, I can deal with that. Now let's print what that returns with
code:
wstring name = GetPipeName();
cout << name << endl;

quote:

Error 1 error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'std::wstring' (or there is no acceptable conversion)

I feel like I'm sliding into something from which even light cannot escape.

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
std::wcout

raminasi
Jan 25, 2005

a last drink with no ice

epswing posted:

Ok, I'm on board, but where should I be doing #undef UNICODE?

If I put it at the top of the cpp file which contains CWinApp theApp; (which I assume to be the entry point of the app), or at the top of stdafx.h, I still get


e: I'd like to know how to figure out which file I need to edit, just as much as I'd like to know which file I need to edit.

Don't explicitly #undef UNICODE, just change your character set to "Use Multi-Byte Character Set" in your Project Properties > Configuration Properties > General page.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

epswing posted:

I feel like I'm sliding into something from which even light cannot escape.

That's totally a fair concern; it's kindof like const-correctness in that it's easy to do the right thing from the start, but if you have a ton of Unicode-incorrect code it's annoying to retroactively fix things. Although I would note that it's always easier to retroactively fix things when you have less code (i.e. right now) than when you have more (i.e. when you get around to fixing your Unicode bugs in five years).

The nice thing is that getting things right is pretty easy if the libraries you're using support it properly, and Windows and the STL both do. In the STL, you basically just have to put 'w' before every type that's normally defined in terms of 'char' (strings, streams, etc.). In the Windows API, it's a 'W' suffix, or you can use the unsuffixed name and rely on the macro.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

epswing posted:

Easy enough, but now this means to concat two strings, I can't just do "one" + "two", it needs to be
You can't do that even with non-wide strings, and return L"\\\\.\\pipe\\" + this->pipeName; works exactly the same as it would with no L and pipeName a std::string.

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
The is one annoying flaw in the C++ wide string stuff, though: The standard exception types only use char-based strings, making them even more limited in usefulness.

epswing
Nov 4, 2003

Soiled Meat

Plorkyeran posted:

You can't do that even with non-wide strings, and return L"\\\\.\\pipe\\" + this->pipeName; works exactly the same as it would with no L and pipeName a std::string.

This doesn't sound too bad, actually.

epswing
Nov 4, 2003

Soiled Meat
C# has these neat IsConnected and IsMessageComplete properties of PipeStreams, making it easy to delimit messages that are larger than BUFFER_SIZE:

code:
byte[] buffer = new byte[BUFFER_SIZE];

while (pipe.IsConnected)
{
    using (var memoryStream = new MemoryStream())
    {
        do
        {
            memoryStream.Write(buffer, 0, pipe.Read(buffer, 0, buffer.Length));
        } while (!pipe.IsMessageComplete);

        // do something with memoryStream here
    }
}
The inner do {} loop will break even though there's more to read in the stream, which I'll pick up next time around (assuming the pipe is still connected). The benefit here is that I don't need to send some control character to break the inner loop.

I've created a named pipe in C++ using CreateNamedPipe, and I'm looping over ReadFile in the same manner. Is there any way I can accomplish the same thing, or do I have to send some kind of control character to indicate the end of one message and the beginning of another?

I could use while (bytesRead == BUFFER_SIZE) to indicate there's more data in the message :v: (which of course doesn't work if the message is exactly BUFFER_SIZE).

Edit: might as well paste the code so y'all can have a chuckle, right?

code:
void Pipe::Read()
{
    char buffer[PIPE_BUFFER_SIZE];
    vector<string> message;
    DWORD bytesRead = 0;
    bool stillConnected = false;

    do
    {
        message.clear();

        do
        {
            bytesRead = 0;
            stillConnected = ReadFile(
                this->pipe,
                buffer,
                PIPE_BUFFER_SIZE,
                &bytesRead,
                NULL
            );

            if (bytesRead > 0)
            {
                string s = string(buffer, bytesRead);
                cout << "received: " << s << endl;
                message.push_back(s);
            }
        }
        while (bytesRead == PIPE_BUFFER_SIZE); // lol

        // do something with message here
    }
    while (stillConnected);

    printf("done reading from pipe");
}

epswing fucked around with this message at 16:34 on Sep 17, 2010

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
What's a message and how does the .NET class determine what differentiates messages?

epswing
Nov 4, 2003

Soiled Meat

Mustach posted:

What's a message

I should have clarified.

On the client (sending) side, assuming a buffer size of 16, I want to send a message, and do something with it on the server side.

code:
// client side
client.send("here's a long message") // 21 chars 
client.send("another message")       // 15 chars 
On the server (receiving) side, I want to process "here's a long message" and then process "another message". Using the above code, the buffer would fill up to 16 ("here's a long me") and add that to the vector<string>. Then loop around and grab the remainder ("ssage") and again add it to the vector. *I can then join the strings in the vector (producing "here's a long message"), do something with it, clear the vector, and start reading the next message.

* right here is where my control character(s) would go, to break out of the inner loop

Mustach posted:

and how does the .NET class determine what differentiates messages?

I don't know, but thinking about it now, their PipeStream abstraction must be sending control characters under the hood.

epswing fucked around with this message at 16:55 on Sep 17, 2010

epswing
Nov 4, 2003

Soiled Meat
Let me simplify my question. Say I have two programs connected by a pipe. I wish to send some xml/json/etc data from one program to the other. The receiving program needs to do something with this bundle of data, which I'll call a "message". The receiving program loops over ReadFile, filling a buffer with whatever comes down the pipe.

In the case that a message is larger than the buffer, and is split across several calls to ReadFile, how would you (A) accumulate and put together the message (which you need to do before processing it) and (B) differentiate between messages?

Am I thinking about this entirely the wrong way?

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

epswing posted:

Let me simplify my question. Say I have two programs connected by a pipe. I wish to send some xml/json/etc data from one program to the other. The receiving program needs to do something with this bundle of data, which I'll call a "message". The receiving program loops over ReadFile, filling a buffer with whatever comes down the pipe.

In the case that a message is larger than the buffer, and is split across several calls to ReadFile, how would you (A) accumulate and put together the message (which you need to do before processing it) and (B) differentiate between messages?

Am I thinking about this entirely the wrong way?
If the receiver needs to still respond to other things, then you need a global/static/heap buffer you can collect the message into, which you keep filling until you have a while message. If the receiver can just wait until the message is complete or the connection breaks, then you can just use a blocking read of the appropriate size, if you know in advance what the appropriate size is.

For my things, I like to start each message with a message size, so you know how much data you need to accumulate. Since I do games, I don't want to block, I make my sockets or pipes state-machines with states "connecting", "waiting", "partialmessage", "disconnected".

Then for each check it goes something like
code:
if (state==waiting) {
  try to read a message size
  if I got one, change state to partialmessage, currentpos to sizeof(size)
     change target size to the size, and stick that size so far in the buffer
}
if (state==partialmessage) {
  try to read (targetsize-currentpos) into the buffer
  if it's done, deal with the now complete message then state=waiting, currentpos=0
  if I got some but not enough, update currentpos
  if the connection dropped, disconnect
}

epswing
Nov 4, 2003

Soiled Meat

epswing posted:

how would you (B) differentiate between messages?

http://msdn.microsoft.com/en-us/library/aa365467(v=VS.85).aspx posted:

If a named pipe is being read in message mode and the next message is longer than the nNumberOfBytesToRead parameter specifies, ReadFile returns FALSE and GetLastError returns ERROR_MORE_DATA. The remainder of the message can be read by a subsequent call to the ReadFile
:ughh: sorry

roomforthetuna posted:

start each message with a message size

Neato, like Content-Length in HTTP.

Also, I spin off a thread for reading, which blocks in a loop until there's stuff to read. I think that will work for my purposes.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

epswing posted:

Neato, like Content-Length in HTTP.

Also, I spin off a thread for reading, which blocks in a loop until there's stuff to read. I think that will work for my purposes.
Yeah, using blocking functions can make the reading loop a lot easier, though multi-threading comes with its own can of worms of course. Make sure you critical-section the code where you stack and unstack your completed messages, and have some way to end the thread cleanly.

Having a binary message size header is certainly more efficient and simpler than reading to a delimeter (and easier than HTTP's Content-Length header because with HTTP you still have to read the header itself with delimeters before you can do a big known-size data burst), though data in binary also carries its own can of worms (byte orders if you're not sure you're sticking with one OS/hardware, and it's not good for readability/debugging).

pseudorandom name
May 6, 2007

And you have to keep in my that whomever is sending the message could be lying about the buffer size.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

pseudorandom name posted:

And you have to keep in my that whomever is sending the message could be lying about the buffer size.
Only to the point of "if the message is ridiculously large then just drop the connection". Other than that a false size is no problem - obviously you'll want to validate all the messages anyway though, and size can be a contributor. But if you get a 'size' that says 20 bytes and the message is 500 bytes, that won't be a buffer overflow or anything, it'll just be a crap busted message 20 bytes long followed by a nonsense-data 'size' of the next message taken from the middle of 500 bytes.

vvvv Yeah, I did say you need a way to pre-emptively shut a blocking thread down if it's threaded. If it's not threaded or blocking, per my pseudocode, then a lack of data can't cause a hang. That's not just an issue with false sizes though, it's also an issue with clients crashing, and just as much of a problem either way if you use delimeters (malicious client can stop sending data without sending a delimeter).

roomforthetuna fucked around with this message at 21:00 on Sep 18, 2010

Vanadium
Jan 8, 2005

It might cause your program to hang if it promises to send two bytes but only sends one!!

Deep Dish Fuckfest
Sep 6, 2006

Advanced
Computer Touching


Toilet Rascal
Quick question: where do I learn about templates and their uses? Beyond the typical "let's make a template so a class can work with multiple types of scalars!" example you get at the end of most C++ books, I mean. The "Other recommended books" list in the op lists "C++ Templates: The Complete Guide", is that what I should get or are there better resources?

For background, I like to think of myself as a not-completely-incompetent C++ programmer, but I'm clueless when it comes to templates beyond the very basics. I'm currently using a package which makes heavy use of them in ways that make absolutely no sense to me and which might as well be powered by magic and the devil himself. I'd like to fix that.

Vanadium
Jan 8, 2005

Modern C++ Programming by Alexandrescu does all kinds of cool template gimmicks!!

That Turkey Story
Mar 30, 2003

YeOldeButchere posted:

Quick question: where do I learn about templates and their uses? Beyond the typical "let's make a template so a class can work with multiple types of scalars!" example you get at the end of most C++ books, I mean. The "Other recommended books" list in the op lists "C++ Templates: The Complete Guide", is that what I should get or are there better resources?

That's a great book, C++ Template Metaprogramming is also very good, and if you want to read up on templates and generic programming in practice you can check out The Boost Graph Library, especially if you have an interest in graph theory. Despite the latter being about a specific library, you can learn a lot from its design as it's one of the greatest C++ libraries in existence and also entirely template-based.

Dooey
Jun 30, 2009
code:
std::vector<int> vec = some_func_returning_a_vector();
for (int i = 0; i < vec.size(); ++i) {
    if (some_condition) {
        vec.erase(vec.begin() + i);
        --i;
    }
}
Is this the proper way to loop through a vector (or any container really) and remove the items that match some condition?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Dooey posted:

code:
std::vector<int> vec = some_func_returning_a_vector();
for (int i = 0; i < vec.size(); ++i) {
    if (some_condition) {
        vec.erase(vec.begin() + i);
        --i;
    }
}
Is this the proper way to loop through a vector (or any container really) and remove the items that match some condition?

No specific C++ experience, but I'm going to go with "no", at least as far as a C++ vector goes. Taking elements out of the middle of a vector requires copying all of the following elements. If you're going to be removing a significant proportion of the elements, you're probably better off copying all of the ones you want to keep to a new vector instead.

Even when dealing with a linked-list type structure such as a deque, you should be using an iterator to traverse the list and remove the elements.

Jabor fucked around with this message at 10:20 on Sep 19, 2010

Dooey
Jun 30, 2009
OK yeah that makes sense. Thanks.

shrughes
Oct 11, 2008

(call/cc call/cc)

Jabor posted:

No specific C++ experience, but I'm going to go with "no". Taking elements out of the middle of a vector requires copying all the remaining elements. If you're going to be removing a significant proportion of the elements, you're probably better off copying all of the ones you want to keep to a new vector instead.

Or you can walk two iterators through the vector, a writing iterator and a reading iterator that is always >= the writer.

Dooey: you might want to use std::remove_if.

EdiT:

Jabor posted:

Even when dealing with a linked-list type structure such as a deque, you should be using an iterator to traverse the list and remove the elements.

Just a heads up, a deque is not necessarily a linked list.

shrughes fucked around with this message at 10:23 on Sep 19, 2010

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

shrughes posted:

Just a heads up, a deque is not necessarily a linked list.

As I mentioned, I'm not a C++ guy. Checking the docs again, this is correct. Replace "deque" in my post above with a suitable collection-that-supports-efficient-removals-from-the-middle.

ehnus
Apr 16, 2003

Now you're thinking with portals!

Jabor posted:

No specific C++ experience, but I'm going to go with "no", at least as far as a C++ vector goes. Taking elements out of the middle of a vector requires copying all of the following elements. If you're going to be removing a significant proportion of the elements, you're probably better off copying all of the ones you want to keep to a new vector instead.

Even when dealing with a linked-list type structure such as a deque, you should be using an iterator to traverse the list and remove the elements.

You could swap with end() - 1 and then pop_back(), although this does change the order of the elements in the vector.

Adbot
ADBOT LOVES YOU

MutantBlue
Jun 8, 2001

Dooey posted:

code:
std::vector<int> vec = some_func_returning_a_vector();
for (int i = 0; i < vec.size(); ++i) {
    if (some_condition) {
        vec.erase(vec.begin() + i);
        --i;
    }
}
Is this the proper way to loop through a vector (or any container really) and remove the items that match some condition?

Replace that for loop with:
code:
vec.erase(remove_if(vec.begin(), vec.end(), some_condition), vec.end());

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply