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
That Turkey Story
Mar 30, 2003

vanjalolz posted:

Ha Ha what the hell? Do Boost pointers actually add anything useful to warrant such terrible syntax?

They're not different pointer types, it's just a metafunction that yields a regular pointer.

Avenging Dentist posted:

Quick question, which hopefully That Turkey Story can answer: is there a library to support properties in C++ (a la C#)? If not, I'm going to write one...

I though I had this discussion with you but maybe not. I actually made a library for properties in C++ a couple years ago but it's impossible to make one without overhead except in certain cases unless you complicate your encapsulating class definition (and in the case of empty types, you're out of luck). The reason is that if you want the standard . syntax, you generally have to make a dummy object that needs access to the encapsulating class, which you can't directly do without storing redundant information.

A quick example of a common situation that causes problems is a container with begin, end, and size properties. To get around having to have the internal property object need access to the encapsulating object to pull out iterator data, you can just store the begin iterator inside of the begin property and store the end iterator inside of the end property, but then what do you do for size? Often size isn't explicitly store in containers at all and is instead just calculated on demand, such as internally doing end() - begin() when you call size() for std::vector (which is very common). The issue is, how does your size property dummy object get access to the begin and end iterators? It can't directly access them because they are contained in some object other than itself that it does not directly or indirectly encapsulate. Since you are going to be using overloaded operator = and an overloaded conversion operator for access and because . itself is not overloadable, you have no way of passing a reference to the data transparently during the access. Instead you have to do something like always store a reference to the encapsulating object from within your property, which just needlessly bloats the size of your encapsulating object and also adds some additional overhead such as for initalization. Not only that, but the maker of the type now needs to explicitly initialize the property in his constructor, which makes his own code more complex.

Another trivial example that causes problems is a bunch of properties that map into a bit-field. You can't stick part of the bit-field in each member, so for each of those properties, you're going to be taking some damage. Now all of a sudden you need O(N) redundant self-references stored indirectly in your object, where N is the number of bits you are accessing, with each property generally taking sizeof(void*) space a piece, and each needing to be separately initialized in the constructor.

Then there is the issue of properties with virtual accessors. If you accept all of the problems mentioned above and continue on, virtual functions add even more hassles. Why? Because now the implementation of your accesses needs to be a call that is forwarded to a virtual function in your encapsulating object, since if you just directly make the functions virtual in your property dummy object, deriving from the encapsulating object won't allow you to override your property's virtual functions (and even if you could, it would still imply that each of your properties with virtual accessors has its own vtable pointer, which again would cause hell to the size and initialization of your overall object).

All of these problems are pretty much show-stoppers, at least with the common C++ philosophy. If you still want to go on, what I ended up doing, just because I refused to be defeated and wanted to see something remotely similar to properties even though I'd never actually use it, is overload a binary operator for accessing the name of the property. Then, since that function has access to both the encapsulating object and whatever object you are using for a name, you can create a simple temporary during the access which holds a reference to the encapsulating data and that has overloaded operator = and conversion. I chose operator ->* since it made the most sense.

So in the end, for the no overhead approach you can get access like:

code:
size_type const current_size = my_container->*size;
my_container->*size = 10; // resize to 10
Where size is just a dummy object stored at namespace scope, so you might even need to qualify it depending on context. This can be optimized to absolutely no overhead, requires no unnecessary data to be stored within the container, and can even be implemented entirely outside of the class definition at namespace scope. Of course, once you start using operator ->* instead of operator . you completely get rid of many of the use-cases for properties, so it becomes somewhat pointless. In the end, it's just not worth trying to make a library for properties in C++ as you really need language support, or at the very least, an overloadable . operator, and even then you still have the problem of namespace qualification.

Adbot
ADBOT LOVES YOU

Wuen Ping
Feb 2, 2007
... and there was a proposal to the committee about adding language support for properties. It died a horrible death. So don't hold your breath.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

That Turkey Story posted:

:words:

There's always the option of using memory offsets to communicate among properties! :v:

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.

That Turkey Story posted:

code:
size_type const current_size = my_container->*size; my_container->*size = 10; // resize to 10

I just realized that Qt doesn't actually do this at all - all its "properties" do is declare attach a name to the getter/setter functions that can be used from language bindings that actually support properties; from C++ you still have to use the functions.

Iori Branford
May 5, 2004
I play co-op with bots.
There's this struct that I want to use as a game piece and as a base for game pieces:
code:
[s]typedef [/s]struct Actor
{
  ...
  virtual void Update( float dframes = 1 ) 
  {
    //  update position and animation
  };
  ...
}
[s]Actor[/s];
If I try to call Update on an Actor reference, it causes a segfault. Why can't I do this?

Never mind. Some leftover code was tampering with the Actor I was trying to Update.

Iori Branford fucked around with this message at 09:29 on May 17, 2008

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
You need to provide more context.

P.S. Don't do "typedef struct", it's not necessary in C++.

Creepy Doll
Apr 20, 2008
edit: Issue resolved so you may want to just skip over this unless you're interested in this kind of stuff... End result was sockets weren't getting properly closed and select() on them was making memory allocation go through the roof.

This may well belong in a linux questions thread I'm not sure... I am however sure it's given me a lot of headache after spending a couple of weeks on and off trying to solve it.

In fact maybe I should just be posting a thread as it's not exactly a simple question, but I'm just going to shoot here anyway as it seems most appropriate.


Situation: I'm developing a chat server/client in parallel... The client is made in flex to be embedded into peoples web pages, but has no issues.

The server is made to run on a linux server(developed in eclipse using the cygwin CDT oolchain, then rebuilt on the target server), uses berkeley sockets and a single thread, using a select statement to check for updated sockets.

The issue however is with after a random amount of time, generally ranging from 3-8 hours, it gets killed by oom killer. The issue occurs in both the forking daemon process version I made, and the "normal" active process.

I've been trying to trawl over logs and have gone over all the relevant code in the main loop that could be causing a memory leak but have no clue... I could intercept the kill signal to do some processing there, but I believe it'd be a bad idea to just ignore it... If I was to intercept the signal what kind of data should I try to pull before letting the app die? How would I get it.

Including some of the relevant source as well as the dmesg log of one of the crashes should anybody be willing to take a peek:

Main loops and non-trivial functions used by it(not including the actual message processing calls... The crash occurs regardless of actual socket activity

code:
// main loop
        while(true)
	{
		if(!GetComms(&sockIncoming) || g_exitFlag)
			break;
	}


// GetComms
int GetComms(Listener * incoming)
{
	static fd_set socks;
	static int highSock = 0;
	
	static UserList users;
	
	FD_ZERO(&socks);
	UpdateSocks(&socks, incoming, &highSock, &users);
	
	fd_set tempSocks;
	memcpy(&tempSocks, &socks, sizeof(socks));
	
	timeval timeOut;
	timeOut.tv_sec = 10;
	timeOut.tv_usec = 0;
	
	int results = select(highSock+1, &tempSocks, (fd_set*)0, (fd_set*)0, &timeOut);
	
	if(results < 0)
	{
		incoming->AddLog("Error in UpdateSocks. Negative results on select");
		return 0;
	}
	
	if(results > 0)
	{
		return ProcessSocks(&tempSocks, incoming, &users);
	}		
	return 1;
}

void UpdateSocks(fd_set * socks, Listener * incoming, int * highSock, UserList * users)
{
	FD_ZERO(socks);
	FD_SET(incoming->GetSock(), socks);
	*highSock = incoming->GetSock();
	
	users->UpdateSet(socks, highSock);
}

void UserList::UpdateSet(fd_set * socks, int * highSock)
{
	if(m_users.empty())
		return;
	
	for(list<User>::iterator it = m_users.begin(); it != m_users.end(); it++)
	{
		if(it->IsValid())
		{
			it->AddToList(socks, highSock);
		}
	}
}

bool User::AddToList(fd_set * socks, int * highSock)
{
	if(m_sock.IsValid())
	{
		FD_SET(m_sock.GetSock(), socks);
		if(m_sock.GetSock() > (*highSock))
			*highSock = m_sock.GetSock();
		
		return true;
	}
	else
		return false;
}
dmesg:
code:
chatserver invoked oom-killer: gfp_mask=0x201d2, order=0, oomkilladj=0

Call Trace:
 [<ffffffff800bed05>] out_of_memory+0x8e/0x2f5
 [<ffffffff8000f071>] __alloc_pages+0x22b/0x2b4
 [<ffffffff80012720>] __do_page_cache_readahead+0x95/0x1d9
 [<ffffffff800618e1>] __wait_on_bit_lock+0x5b/0x66
 [<ffffffff880fbc61>] :dm_mod:dm_any_congested+0x38/0x3f
 [<ffffffff800130ab>] filemap_nopage+0x148/0x322
 [<ffffffff800087ed>] __handle_mm_fault+0x1f8/0xdf4
 [<ffffffff80064a6a>] do_page_fault+0x4b8/0x81d
 [<ffffffff80013333>] tcp_poll+0x0/0x12f
 [<ffffffff8005bde9>] error_exit+0x0/0x84

Mem-info:
Node 0 DMA per-cpu:
cpu 0 hot: high 0, batch 1 used:0
cpu 0 cold: high 0, batch 1 used:0
cpu 1 hot: high 0, batch 1 used:0
cpu 1 cold: high 0, batch 1 used:0
cpu 2 hot: high 0, batch 1 used:0
cpu 2 cold: high 0, batch 1 used:0
cpu 3 hot: high 0, batch 1 used:0
cpu 3 cold: high 0, batch 1 used:0
Node 0 DMA32 per-cpu:
cpu 0 hot: high 186, batch 31 used:30
cpu 0 cold: high 62, batch 15 used:49
cpu 1 hot: high 186, batch 31 used:29
cpu 1 cold: high 62, batch 15 used:48
cpu 2 hot: high 186, batch 31 used:30
cpu 2 cold: high 62, batch 15 used:59
cpu 3 hot: high 186, batch 31 used:30
cpu 3 cold: high 62, batch 15 used:49
Node 0 Normal per-cpu:
cpu 0 hot: high 186, batch 31 used:15
cpu 0 cold: high 62, batch 15 used:54
cpu 1 hot: high 186, batch 31 used:68
cpu 1 cold: high 62, batch 15 used:55
cpu 2 hot: high 186, batch 31 used:172
cpu 2 cold: high 62, batch 15 used:14
cpu 3 hot: high 186, batch 31 used:45
cpu 3 cold: high 62, batch 15 used:60
Node 0 HighMem per-cpu: empty
Free pages:       40792kB (0kB HighMem)
Active:1118174 inactive:897487 dirty:0 writeback:0 unstable:0 free:10198 slab:3934 mapped-file:28 mapped-anon:2015317 pagetables:9900
Node 0 DMA free:11172kB min:12kB low:12kB high:16kB active:0kB inactive:0kB present:10820kB pages_scanned:0 all_unreclaimable? yes
lowmem_reserve[]: 0 3511 8056 8056
Node 0 DMA32 free:23164kB min:5004kB low:6252kB high:7504kB active:1966912kB inactive:1572876kB present:3596256kB pages_scanned:7479413 all_unreclaimable? yes
lowmem_reserve[]: 0 0 4544 4544
Node 0 Normal free:6456kB min:6476kB low:8092kB high:9712kB active:2463032kB inactive:2059696kB present:4654072kB pages_scanned:13406328 all_unreclaimable? yes
lowmem_reserve[]: 0 0 0 0
Node 0 HighMem free:0kB min:128kB low:128kB high:128kB active:0kB inactive:0kB present:0kB pages_scanned:0 all_unreclaimable? no
lowmem_reserve[]: 0 0 0 0
Node 0 DMA: 3*4kB 3*8kB 4*16kB 6*32kB 4*64kB 3*128kB 0*256kB 0*512kB 2*1024kB 0*2048kB 2*4096kB = 11172kB
Node 0 DMA32: 5*4kB 3*8kB 1*16kB 0*32kB 1*64kB 0*128kB 0*256kB 1*512kB 0*1024kB 1*2048kB 5*4096kB = 23164kB
Node 0 Normal: 14*4kB 2*8kB 1*16kB 1*32kB 1*64kB 1*128kB 0*256kB 0*512kB 0*1024kB 1*2048kB 1*4096kB = 6456kB
Node 0 HighMem: empty
Swap cache: add 508414, delete 508414, find 75/128, race 0+0
Free swap  = 0kB
Total swap = 2031608kB
Free swap:            0kB
2228224 pages of RAM
182590 reserved pages
1052 pages shared
0 pages swap cached
Out of memory: Killed process 5866 (chatserver).

Creepy Doll fucked around with this message at 11:18 on May 20, 2008

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.
Haven't taken the time to read your code, but change "while true" to "for (int i = 0; i < 10; ++i)" or something so that it'll only run a few times. Then run it through valgrind with the --leak-check flag and it should tell you where the most obvious leaks are.

Creepy Doll
Apr 20, 2008

JoeNotCharles posted:

Haven't taken the time to read your code, but change "while true" to "for (int i = 0; i < 10; ++i)" or something so that it'll only run a few times. Then run it through valgrind with the --leak-check flag and it should tell you where the most obvious leaks are.

Sweet, I wasn't aware of valgrind, installing it now and going to see what it comes up with, thanks.

Kerris
Jul 12, 2006
Don't you fucking dare compliment a woman's voice on the forums, you fucking creepy stalker.
Is Splint still worth using, or does Valgrind covers everything that Splint does?

Creepy Doll
Apr 20, 2008
Welp, there was a couple of minor errors along the lines of delete'ing where I should've delete[]'d, but they weren't in the main loop, but rather in the shutdown and such...

Fixed those and down to 0 errors + 4 suspended errors from 1 context...

Got the program running in the background now and hoping for the best, but considering the severity of the errors that were there(a total of maybe 200-300 bytes worth of allocated memory that wasn't properly unallocated), I doubt it's fixed... We shall see.

Either way, great tool and thanks for pointing to it! Should help in the future too.

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.

Creepy Doll posted:

Welp, there was a couple of minor errors along the lines of delete'ing where I should've delete[]'d, but they weren't in the main loop, but rather in the shutdown and such...

Hmm, that gives me an idea:

Valgrind checks for actual errors, but also for possible memory leaks, which are things which are allocated during the program that aren't freed when the program ends. If your program keeps allocating memory in each loop, but doesn't free it correctly until shutdown, Valgrind wouldn't catch it (because it IS freed at shutdown). That would give exactly the symptoms you see - if you run it for a while with "while (true)" the memory will grow without bound, but if you limit it to a few iterations Valgrind won't report a problem.

I'm not sure if Valgrind can give a sensible report on leaks if the memory actually gets exhausted while it's running. You could try going back to "while (true)" and see what happens (or better yet, see if you can find anything about it in the Valgrind docs). Or maybe try commenting out all your cleanup code on exit so that Valgrind will report more "leaks", some of which will be bogus and some of which will be your actual leak.

Creepy Doll
Apr 20, 2008
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
I'll have a look at that, however, there's barely any actual allocation going on that isn't handled by the stl classes... Most of my user and room management is all done with stl::list and stl::map... Which I would like to hope are leak free.

welp, allowing it to run for an hour or so I got this
code:
==17443== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 1)
==17443== malloc/free: in use at exit: 1,066 bytes in 24,292,922 blocks.
==17443== malloc/free: 24,293,861 allocs, 939 frees, 117,114 bytes allocated.
==17443== For counts of detected errors, rerun with: -v
==17443== searching for pointers to 24,292,922 not-freed blocks.
==17443== checked 702,544 bytes.
==17443==
==17443== LEAK SUMMARY:
==17443==    definitely lost: 498 bytes in 24,292,669 blocks.
==17443==      possibly lost: 0 bytes in 0 blocks.
==17443==    still reachable: 568 bytes in 253 blocks.
==17443==         suppressed: 0 bytes in 0 blocks.
==17443== Rerun with --leak-check=full to see details of leaked memory.
Reading the docs, the suppressed errors are stuff from libraries...

I never concerned myself with memory management beyond making sure anything I allocated I got rid of down the line, so I'm not 100% sure of the meaning of this report, but I think it means 498 bytes total in 24,292,669 blocks? That would mean a lot of blocks allocated with 0 memory? Why would this be happening?

edit: I'm going to give massif a shot to see if it can tell me what the hell is allocating all that memory, because it sure as hell isn't being done by any new/mallocs explicitly within my program.

edit^2: And the results are in... For some reason extra poo poo is allocated to the stack in what massif describes as extra-heap(B)...

massif docs posted:

• The number of extra heap bytes allocated at that point. This reflects the number of bytes allocated in excess of
what the program asked for. There are two sources of extra heap bytes.
First, every heap block has administrative bytes associated with it. The exact number of administrative bytes
depends on the details of the allocator. By default Massif assumes 8 bytes per block, as can be seen from the
example, but this number can be changed via the --heap-admin option.
Second, allocators often round up the number of bytes asked for to a larger number. By default, if N bytes
are asked for, Massif rounds N up to the nearest multiple of 8 that is equal to or greater than N. This is typical
behaviour for allocators, and is required to ensure that elements within the block are suitably aligned. The
rounding size can be changed with the --alignment option, although it cannot be less than 8, and must be a
power of two.

The actual data(a couple of samples of it... it's just a linear increase throughout the program):
code:
--------------------------------------------------------------------------------
  n        time(i)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
--------------------------------------------------------------------------------
  0              0                0                0             0            0
  1     26,481,089          164,160           42,652       121,508            0
  2     59,110,337          332,352           42,652       289,700            0
  3     78,181,313          430,656           42,652       388,004            0
  4    110,289,089          596,160           42,652       553,508            0
  5    126,777,537          681,152           42,652       638,500            0
  6    152,354,497          812,992           42,652       770,340            0
.
.
.
 39    956,040,411        4,326,904           42,951     4,283,953            0
 40    977,197,899        4,416,888           42,951     4,373,937            0
 41    998,355,387        4,506,872           42,951     4,463,921            0
 42  1,019,512,875        4,596,856           42,951     4,553,905            0
 43  1,040,670,363        4,686,840           42,951     4,643,889            0
.
.
.
 62  1,381,970,289        6,138,416           42,951     6,095,465            0
 63  1,398,459,135        6,208,544           42,951     6,165,593            0
 64  1,414,947,981        6,278,672           42,951     6,235,721            0
 65  1,431,436,827        6,348,808           42,951     6,305,857            0
 66  1,447,925,673        6,418,936           42,951     6,375,985            0

Creepy Doll fucked around with this message at 08:55 on May 20, 2008

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.
If you're stuffing stuff into a list but never removing it from a list, that's a "leak" in the sense that you're adding more and more stuff and never getting rid of it. So that could be your problem.

EDIT: most things you put into an STL data structure use the copy constructor, so if you create a local object on the stack it automatically copies it onto the heap for you, which is where the new memory comes from:

code:
stl::list<SomeObject> g_objectlist;

void do_something(void) {
  SomeObject o;
  g_objectlist.push_back(o);
  // end of do_something: o gets free'd, but a copy still exists in g_objectlist
};
If the lists and maps you're talking about go out of scope themselves, that does free all their contents of course.

I'm really not sure how to interpret the summary it gave you - could it be 24,292,669 blocks of 498 bytes each? (I didn't think that was how it reported them, but I can't figure any other sensible way to interpret that.)

Have you tried using the --leak-check=full flag it gave? (I meant to tell you to use that from the start, but I forgot the exact syntax so I just said "--leak-check" - sorry.)

JoeNotCharles fucked around with this message at 08:44 on May 20, 2008

Creepy Doll
Apr 20, 2008
I did the leak check full flagit didn't give any additional info...

User connections are also logged as are room creations and neither of them is happening unexpectedly.

I appear to be onto something now... It seems none of this actually occurs until the first user disconnects, and then memory starts getting consumed... It's just extremely slow without something like massif increasing the consumed memory by huge amounts while profiling it... I guess something is probably wrong with my method of removing a user or disconnecting a socket...

edit: Looks like I found the problem. For some dumb reason when checking for received bytes on the socket I was checking less than 0 and more than 0, but not for zero(correct shutdown of the socket).
Oddly enough this was not an issue on the cygwin setup running off my pc... I assume cygwin uses winsock to emulate berkeley sockets and somewhere in that process a correct shutdown(0 received) becomes an error(-1)...

Either way, thanks a lot for the tips, without them I'm sure this would've taken a lot more work.

Edit^2:

Down to no leaked memory so looks like it's all good. I guess select()ing on a correctly closed socket is apparently a very bad thing.

Creepy Doll fucked around with this message at 11:16 on May 20, 2008

Viper2026
Dec 15, 2004
I got iRaped by Steve Jobs and all I got was this custom title.
I'm trying to write a merge sort function, but I keep getting errors that have me stumped.

At the very end of my merge_sort I call a function merge() which returns a string*, yet when I call my function like this:

code:
string *result;
result = new string[sizeof(list)];
result = merge(left_half, right_half);

I declare my left and right arrays like this (previously 
calling string *left_half, *right_half):

number is sizeof(list)

	if(number % 2 == 0){ //list is even in size
		left_half = new string[number / 2], 
		right_half = new string[number / 2];
		even = true;
	}
	else{ //list is odd
		left_half = new string[number / 2], 
		right_half = new string[(number / 2) + 1];
		even = false;
	}
I am getting the error:
error: no matching function for call to 'merge(std::string*&, std::string*&)'

the prototype of my merge function is:
code:
string* merge(string *list1, string *list2)
EDIT:
heh...got it, I am stubborn with my main files and I always like to define the functions first instead of putting the prototype then defining them after my main. It turns out merge needed to be above merge_sort :downs:

Viper2026 fucked around with this message at 02:18 on May 21, 2008

Adhemar
Jan 21, 2004

Kellner, da ist ein scheussliches Biest in meiner Suppe.

Viper2026 posted:

code:
	if(number % 2 == 0){ //list is even in size
		left_half = new string[number / 2], 
		right_half = new string[number / 2];
		even = true;
	}
	else{ //list is odd
		left_half = new string[number / 2], 
		right_half = new string[(number / 2) + 1];
		even = false;
	}

Since you solved your own problem, I'd like to just add that you don't need that even/odd business; you can just split down the middle (length / 2). If the length is odd, one part will be one element larger than the other, but that's not a problem.

Wuen Ping
Feb 2, 2007

Viper2026 posted:

I'm trying to write a merge sort function,
:words:

The real solution to your problem is to stop right there, and use std::sort() and/or std::merge() instead. Check out the gratis and very extensive documentation on Dinkumware's STL <algorithm> page if you don't know the STL's API well.

If you do that in future, you won't struggle with the details of algorithms that have already been written 1000 times. The code you wrote in hours would have taken minutes or seconds.

Vanadium
Jan 8, 2005

That sure will go over well in a data structures/algorithms class.

TSDK
Nov 24, 2003

I got a wooden uploading this one

Viper2026 posted:

code:
result = new string[sizeof(list)];
This is almost certainly not doing what you think it's doing.

Stormtrooper
Oct 18, 2003

Imperial Servant
Ok, here's a question. I have a function (below) that accepts a string that's a path to a file, and then opens that file and does stuff. This function can be called from source A or source B. If source A calls this function, and the path has an extended character in it (like "é"), the file fails to open. If source B does the same thing, it works. My thought is that the encoding of the string from source A is somehow messed up - any thoughts about how to fix this? (I'm running this on Windows).
code:
myfunction(string name) {
    ifstream file(name.c_str(), ios::in | ios::binary);
    if(file.is_open()) {
        // do stuff
    } else {
        // error
    }
}
Edit: Solution:
String from source A was utf8-encoded. Converted it to ansi and it worked!

Edit 2: New Question:
Anyone know how to correctly pass cyrillic characters in a path to ifstream?

Stormtrooper fucked around with this message at 19:30 on May 21, 2008

cliffy
Apr 12, 2002

Vanadium posted:

That sure will go over well in a data structures/algorithms class.

If you were doing software development in the real world, then Ping's answer would be correct 99.999...9 % of the time. The biggest boon to productivity is access to libraries that have been thoroughly used, bug-tested/fixed, and tons of space/time efficiency tricks that you never would have thought of or taken forever to get right.

Wuen Ping
Feb 2, 2007

Stormtrooper posted:

Edit 2: New Question:
Anyone know how to correctly pass cyrillic characters in a path to ifstream?

You need to construct a wstring containing the path, then pass that to a wifstream. Cyrillic characters are outside of the ASCII set, so you have to use wide characters. ifstream cannot eat UTF-8 characters.

Vanadium
Jan 8, 2005

cliffy posted:

If you were doing software development in the real world, then Ping's answer would be correct 99.999...9 % of the time. The biggest boon to productivity is access to libraries that have been thoroughly used, bug-tested/fixed, and tons of space/time efficiency tricks that you never would have thought of or taken forever to get right.

All the hay-we-are-using-c++-in-the-industry seem to hate the STL anyway and roll their own non-generic containers :iiam:

Also I think if you are posting on SA about how to implement your own container you are probably not doing software development in the real world.

Stormtrooper
Oct 18, 2003

Imperial Servant

Wuen Ping posted:

You need to construct a wstring containing the path, then pass that to a wifstream. Cyrillic characters are outside of the ASCII set, so you have to use wide characters. ifstream cannot eat UTF-8 characters.
Thanks! I did essentially this and it worked well.

Viper2026
Dec 15, 2004
I got iRaped by Steve Jobs and all I got was this custom title.

Vanadium posted:

That sure will go over well in a data structures/algorithms class.

Yeah...exactly this :(
I need to write this myself and the prof is pretty good about catching people trying to copy/paste.

I gave up on the array approach because it was was simply too complicated and am using vector<string>'s now. But I am still having a problem in that my code does not actually sort my list.

My code is here:
http://rafb.net/p/dLKodz88.html

I call merge_sort on the first 10 elements of the vector (the file parsing is all correct)
When I run it, it all seems to work, but when I go to print out the first 10 elements of my vector they do not appear to be sorted at all.

If anyone can take a look and offer any insight into what my problem might be, I'd appreciate it :)

Paniolo
Oct 9, 2007

Heads will roll.
Your merge_sort returns a vector, but you aren't storing the result. I'm guessing your just printing the unsorted vector again. Look into passing by reference (that will also solve the stack overflow that will occur when you pass a vector of non-trivial size into a recursive sorting function.)

Viper2026
Dec 15, 2004
I got iRaped by Steve Jobs and all I got was this custom title.

Paniolo posted:

Your merge_sort returns a vector, but you aren't storing the result. I'm guessing your just printing the unsorted vector again. Look into passing by reference (that will also solve the stack overflow that will occur when you pass a vector of non-trivial size into a recursive sorting function.)

thanks a lot....I must learn to catch my own stupid mistakes like this

code:
	vector<string> sorted_list = merge_sort(names2, 10);
	
	print_vector(sorted_list, 10);
Now works partially, but result 9 prints:

9. terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check

Would changing my function prototypes to something like
vector<string> merge_sort(vector<string> *list, int number){
and then calling as vector<string> sorted_list = merge_sort(&names2, 10);
fix this?

EDIT: leaving my current code as is and sorting then printing for 100 it crashes at 65, and for 1000 it crashes at 513

Viper2026 fucked around with this message at 00:11 on May 22, 2008

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.

Viper2026 posted:

works partially, but result 9 prints:

9. terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check

Would changing my function prototypes to something like
vector<string> merge_sort(vector<string> *list, int number){
and then calling as vector<string> sorted_list = merge_sort(&names2, 10);
fix this?
std::out_of_range is thrown when you call at() with an index that's less than 0 or greater than or equal to the vector's size.

Viper2026
Dec 15, 2004
I got iRaped by Steve Jobs and all I got was this custom title.

Mustach posted:

std::out_of_range is thrown when you call at() with an index that's less than 0 or greater than or equal to the vector's size.

So does this mean I'm not correctly handling my sizes somewhere in my code?

(I've looked at it for a while now and I can't really see where the problem is, if you might be able to at least give me a hint from the code I linked above I would appreciate it)

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

Viper2026 posted:

So does this mean I'm not correctly handling my sizes somewhere in my code?

(I've looked at it for a while now and I can't really see where the problem is, if you might be able to at least give me a hint from the code I linked above I would appreciate it)

code:
middle = number / 2;
// ...
left = merge_sort(left, middle);
right = merge_sort(right, middle);
Think about what happens when number is odd.

As an aside, you should really reduce the unnecessary copies you're making of your vectors. I count 3 copies of the full vector and 8 copies of the left/right vectors for every step of the merge sort.

Avenging Dentist fucked around with this message at 01:45 on May 22, 2008

Viper2026
Dec 15, 2004
I got iRaped by Steve Jobs and all I got was this custom title.

Avenging Dentist posted:

code:
middle = number / 2;
// ...
left = merge_sort(left, middle);
right = merge_sort(right, middle);
Think about what happens when number is odd.

As an aside, you should really reduce the unnecessary copies you're making of your vectors. I count 3 copies of the full vector and 8 copies of the left/right vectors for every step of the merge sort.

Hmph....yeah I thought that might be an issue, but someone in one of my previous questions said that shouldn't be an issue

So do I want to handle each one differently depending if list.size() is odd or even?

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
You don't need to have any special handling. middle and number-middle, respectively should be sufficient for all cases.

Viper2026
Dec 15, 2004
I got iRaped by Steve Jobs and all I got was this custom title.
That works, thanks a lot

Smackbilly
Jan 3, 2001
What kind of a name is Pizza Organ! anyway?
pthreads question:

Is there any disadvantage to creating lots and lots of threads over the course of a program's execution, if only a couple will exist at any given time?

The context is that I'm writing an app that does asynchronous communication over UDP. Since UDP is unreliable, certain packets that are not ACK'ed after a timeout need to be re-sent. The way I'm currently handling this is:

- send the packet
- spawn a thread which sleeps for the timeout interval
- when the thread wakes, it checks if the ACK has been received yet, if not it calls a timeout handler, which repeats this process.

So every packet that might need to be re-sent gets its own timeout monitor thread. There are only going to be a few (like, 1-5) of these packets pending at any given time, but the program may run for a very long time, so there could easily be hundreds or thousands of short-lived threads created over the course of the program.

Is there any problem with doing this, as long as I make sure to either detatch or join each thread?

I could certainly consolidate timeout handling into one thread, but that would make the code messier and more complicated, so I'm inclined to avoid that unless there is a good reason to do it.

sarehu
Apr 20, 2007

(call/cc call/cc)

Smackbilly posted:

pthreads question:

Is there any disadvantage to creating lots and lots of threads over the course of a program's execution, if only a couple will exist at any given time?

You could just keep a few of them around and reuse them, instead of creating new ones over and over again.

But don't. Do the thing that makes the code messier. It is a local mess (and only if you code it dumbly), not a global mess, so it is fine.

more falafel please
Feb 26, 2005

forums poster

Smackbilly posted:

I could certainly consolidate timeout handling into one thread, but that would make the code messier and more complicated, so I'm inclined to avoid that unless there is a good reason to do it.

It doesn't, really. All you need is a list of packets you have sent out but not received ACKs for yet. When you receive an ACK, remove that packet from the list. Also keep track of the last sent time and resend it every so often. Also, you can average the total round trip time of the last, say 10 packets, and use that as the timeout interval, to avoid sending to frequently or not frequently enough depending on network conditions.

Crash Bandicoot
Feb 23, 2007

by T. Fine
Here's a dumb question with added :words::
I do most of my coding in C#, some Perl, some VB/VBA. I did a semester of C++ in college but we never progressed beyond console applications and some minor pointer fun. Since I'm fed up with knowing the basics of C++ but not enough to do anything useful, I've decided to relearn it, and to that end I'm reading Accelerated C++.

I use Visual Studio 2005 for C# stuff, and I've really grown to like it as a development environment. I'm planning on using Visual C++ 2005 to work along with the book, but I know there are some ways in which it's not like a "standard" C++ compiler. For example, the blank project I've just created has "#include "stdafx.h" at the top and the compiler doesn't like it if I remove it. Trouble is, I don't know if that's a minor VS quirk or just one of many ways VC++ differs from what I'll find in textbooks.

In a nutshell, what I'd like to know is what I should be aware of when learning C++ using Visual Studio. I'd rather know of any common issues ahead of time rather than wait to run into them.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
Just create an empty project in VS2005. There's very little difference in terms of the compiler when writing C++ in Visual Studio (templates are kinda hosed up though).

Adbot
ADBOT LOVES YOU

Paniolo
Oct 9, 2007

Heads will roll.
Stdafx.h is a precompiled header file. You can stick all your library includes in there (from C, STL, Windows, etc.) and it significantly reduces the time of compiling the rest of your project. You can safely delete stdafx.h and specify a new header to precompile later on, but it might require some tweaking of the project settings (even after you delete it, the default project settings still tell the compiler to precompile "stdafx.h" so you have to remove all references to it. Pretty annoying.)

That's all just IDE stuff, in terms of the Microsoft C++ compiler, it's pretty standard stuff. The template problems that were so bad in earlier versions have been fixed to the point where you can use the more experimental boost modules like Spirit just fine. If you create a new blank project in the IDE, add a new blank .cpp file and copy and paste the code from any C++ textbook it will run.

Most of the differences (to the naked newbie eye) between VC++ and gcc are in the preprocessor (different predefined macros, although some like __FILE__ and __LINE__ are the same.) Another significant difference is the handling of 64-bit integers, in VC++ you'd declare them with "__int64" whereas in gcc it's "long long." You shouldn't run into many problems at your level, though.

Edit: woops, VC++ accepts "long long" now, too.

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