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
Plorkyeran
Mar 22, 2007

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

hooah posted:

How does one go about putting function declarations in an .h file, the function definitions in a .cpp, then the main program in another .cpp? I've done this with classes, but this seems to be different (and should be, if I understand my professor correctly).
It mostly isn't.

The obvious wrong thing with that code is that you're using stuff from the std namespace in the header, but the using statements are after the header inclusion. The lazy way to fix this is to move the header inclusion down; the correct way is to slather std:: all over the place in the header (and include the appropriate stdlib headers in the .h).

Adbot
ADBOT LOVES YOU

hooah
Feb 6, 2006
WTF?

Plorkyeran posted:

It mostly isn't.

The obvious wrong thing with that code is that you're using stuff from the std namespace in the header, but the using statements are after the header inclusion. The lazy way to fix this is to move the header inclusion down; the correct way is to slather std:: all over the place in the header (and include the appropriate stdlib headers in the .h).

Ok, it looks like that helped a lot. My one remaining question is how do I deal with the default parameter in split? I tried removing the sep = ' ' bit from the declaration in the .h, but then VS complains that split doesn't take 2 arguments. If I leave sep = ' ' in, I'm told that the default parameter is getting redefined.

Grocer Goodwill
Jul 17, 2003

Not just one kind of bread, but a whole variety.

:lol:

"Using cmph is quite simple. Take a look:
*ten lines of allocs and adapters and configurators*"

Library writers need to learn that libraries are supposed to solve problems.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Grocer Goodwill posted:

:lol:

"Using cmph is quite simple. Take a look:
*ten lines of allocs and adapters and configurators*"

Library writers need to learn that libraries are supposed to solve problems.

The examples are actually mostly configuration.

C++ code:
static cmph_t *
build (void)
{
  cmph_config_t *config;
  cmph_io_adapter_t *io;
  cmph_t *c;
  char **strings = { "foo", "bar", "baz" };

  io = cmph_io_vector_adapter (strings, 3);
  config = cmph_config_new (io);
  cmph_config_set_algo (config, CMPH_BDZ);

  c = cmph_new (config);

  assert (cmph_size (c) == 3));

  cmph_destroy_config (config);
  return c;
}
That's as minimal as it gets for C.

Plorkyeran
Mar 22, 2007

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

hooah posted:

Ok, it looks like that helped a lot. My one remaining question is how do I deal with the default parameter in split? I tried removing the sep = ' ' bit from the declaration in the .h, but then VS complains that split doesn't take 2 arguments. If I leave sep = ' ' in, I'm told that the default parameter is getting redefined.

The declaration should have the default parameter, not the definition (which happens to tell you a lot about how default parameters are implemented in C++).

hooah
Feb 6, 2006
WTF?

Plorkyeran posted:

The declaration should have the default parameter, not the definition (which happens to tell you a lot about how default parameters are implemented in C++).

If I do that, I get a couple of linking errors:
code:
1>proj06-main.obj : error LNK2019: unresolved external symbol "void __cdecl split(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class std::vector<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > > &,char)" (?split@@YAXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AAV?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@2@D@Z) referenced in function _main
1>Proj06.exe : fatal error LNK1120: 1 unresolved externals

bobua
Mar 23, 2003
I'd trade it all for just a little more.

A strange(to me) thing just happened.

code:
std::string foo(int & value)
{
value = value * 2;
if(value > 10)
   return "Frozen Banana.";
value = value * 3;
}
I was under the impression that this would be a compiler error\would not compile. Visual Studio ran it just fine. Shouldn't I HAVE to return a string?

edit: I never use the return string, just the value, so it wasn't causing me any problems.

edit edit: There was a warning, it was just buried in a list of conversion warnings- I'm an idiot.

bobua fucked around with this message at 00:57 on Oct 17, 2013

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

bobua posted:

A strange(to me) thing just happened.

code:
std::string foo(int & value)
{
value = value * 2;
if(value > 10)
   return "Frozen Banana.";
value = value * 3;
}
I was under the impression that this would be a compiler error\would not compile. Visual Studio ran it just fine. Shouldn't I HAVE to return a string?

edit: I never use the return string, just the value, so it wasn't causing me any problems.

"Not all code paths return a value" is just a level 1 warning, it won't stop a compile. You can configure your project to not compile if the code has warnings, you can also set pragmas to ignore warnings.

tractor fanatic
Sep 9, 2005

Pillbug
Not returning when the function has a return type is undefined behavior IIRC. Visual Studio will give you an error if no paths return a value but I don't think the complier is obligated to do anything.

It will also refuse to compile this which may be wrong

C++ code:
void fart(){throw 1;}
int fart2(){
    fart();
}
int main(){
    fart2();
}

Praseodymi
Aug 26, 2010

So I've just got back to Uni and in one class we had to clear the screen to a colour using a memcpy to set every pixel. The "obvious" way was two nested for loops:
code:
 for( int x = 0; x < screeWidth; x++){
   for( int y = 0; y < screeHeight; y++){ 
The lecturer pointed out that this would run faster the other way around, and indeed when he swapped it the fps of the program jumped from 170 to 360. He then tried to speed it up further by doing it the way I had and just running through it as one loop and incrementing i by 4 instead of doing the 4 * (x + y * screenWidth) calculation but when he demonstrated this it only ran at ~270 fps. He didn't really give an answer why on the spot but suspected it might be to do with the compiler's optimisation. Seeing as I was fairly surprised by this and that were getting points for optimisation I was hoping someone here could explain the reason to me.

Acer Pilot
Feb 17, 2007
put the 'the' in therapist

:dukedog:

What's a good way to store/read config settings in a file? I was looking at yaml-cpp but that seems to need boost but if I use boost, I could probably use program-options.

Suggestions?

xgalaxy
Jan 27, 2004
i write code
Didn't realize Visual Studio 2013 was officially released a couple of days ago.
I didn't think it was coming out until mid November.

Qwertycoatl
Dec 31, 2008

Praseodymi posted:

So I've just got back to Uni and in one class we had to clear the screen to a colour using a memcpy to set every pixel. The "obvious" way was two nested for loops:
code:
 for( int x = 0; x < screeWidth; x++){
   for( int y = 0; y < screeHeight; y++){ 
The lecturer pointed out that this would run faster the other way around, and indeed when he swapped it the fps of the program jumped from 170 to 360. He then tried to speed it up further by doing it the way I had and just running through it as one loop and incrementing i by 4 instead of doing the 4 * (x + y * screenWidth) calculation but when he demonstrated this it only ran at ~270 fps. He didn't really give an answer why on the spot but suspected it might be to do with the compiler's optimisation. Seeing as I was fairly surprised by this and that were getting points for optimisation I was hoping someone here could explain the reason to me.

It goes much faster with x on the inside because of the processor caches. When you write your pixel to memory, it doesn't go to memory immediately, it goes into the L1 (then L2) cache, which can batch up 16/128/whatever bytes of writes to send off to memory at once. This works much better if you're writing adjacent memory locations instead of jumping to locations screenWidth apart.

I'm not sure exactly what you're doing in the last part - what's i?

nielsm
Jun 1, 2009



Qwertycoatl posted:

It goes much faster with x on the inside because of the processor caches. When you write your pixel to memory, it doesn't go to memory immediately, it goes into the L1 (then L2) cache, which can batch up 16/128/whatever bytes of writes to send off to memory at once. This works much better if you're writing adjacent memory locations instead of jumping to locations screenWidth apart.

I'm not sure exactly what you're doing in the last part - what's i?

A:
C++ code:
for (size_t y = 0; y < height; y++) {
    for (size_t x = 0; x < width; x++) {
        memcpy(pixels+y*width*4+x*4, &color, 4);
    }
}
This should be the one shown as fast.

B:
C++ code:
size_t pixel_count = width*height;
for (size_t i = 0; i < pixel_count*4; i+=4) {
    memcpy(pixels+i, &color, 4);
}
Supposedly this one ran slower than A?

Hybrid A+B:
C++ code:
for (size_t y = 0; y < height; y++) {
    pixel *row = pixels + y*width*4;
    for (size_t x = 0; x < width; x++) {
        memcpy(row+x*4, &color, 4);
    }
}
You should try how this compares too.

MutantBlue
Jun 8, 2001

I would try the obvious:

C++ code:
std::fill(pixels, pixels + width * height, color);
or
C++ code:
std::fill_n(pixels, width * height, color);

pseudorandom name
May 6, 2007

That won't work if the image has a stride.

MutantBlue
Jun 8, 2001

pseudorandom name posted:

That won't work if the image has a stride.

It also assumes that pixels isn't something like void* or char*. Details...

Foxfire_
Nov 8, 2010

Praseodymi posted:

So I've just got back to Uni and in one class we had to clear the screen to a colour using a memcpy to set every pixel. The "obvious" way was two nested for loops:
code:
 for( int x = 0; x < screeWidth; x++){
   for( int y = 0; y < screeHeight; y++){ 
The lecturer pointed out that this would run faster the other way around, and indeed when he swapped it the fps of the program jumped from 170 to 360. He then tried to speed it up further by doing it the way I had and just running through it as one loop and incrementing i by 4 instead of doing the 4 * (x + y * screenWidth) calculation but when he demonstrated this it only ran at ~270 fps. He didn't really give an answer why on the spot but suspected it might be to do with the compiler's optimisation. Seeing as I was fairly surprised by this and that were getting points for optimisation I was hoping someone here could explain the reason to me.


Post the C and assembly for each version.

Where exactly are your writes going to? Actual memory-mapped device memory will have very different cache behavior from normal memory and I doubt you're actually dealing with it since you would need to be in the kernel.


This is what gcc -O3 spits out for me (I'm pleasantly surprised that it's smart enough to realize that an actual call to memcpy() is dumb for just 4 bytes):

A:
code:
uint32_t height = 1024;
uint32_t width = 1024;
uint32_t color = 0x12345678;
uint8_t pixels[1024 * 1024 * 4];

void A()
{
  for (size_t y = 0; y < height; y++) 
  {
    for (size_t x = 0; x < width; x++) 
    {
      memcpy(pixels+y*width*4+x*4, &color, 4);
    }
  }
}

_A:
LFB0:
	pushl	%ebp
	pushl	%edi
	movl	_height, %edi
	pushl	%esi
	testl	%edi, %edi
	pushl	%ebx
	je	L1
	movl	_width, %esi
	movl	_color, %ecx
	movl	$_pixels, %eax
	xorl	%ebx, %ebx
	leal	0(,%esi,4), %ebp
L3:
	leal	0(%ebp,%eax), %edx
	testl	%esi, %esi
	je	L5
L6:
	movl	%ecx, (%eax)
	addl	$4, %eax
	cmpl	%eax, %edx
	jne	L6
L5:
	incl	%ebx
	movl	%edx, %eax
	cmpl	%edi, %ebx
	jne	L3
L1:
	popl	%ebx
	popl	%esi
	popl	%edi
	popl	%ebp
	ret

B
code:
uint32_t height = 1024;
uint32_t width = 1024;
uint32_t color = 0x12345678;
uint8_t pixels[1024 * 1024 * 4];

void B()
{
  size_t pixel_count = width*height;
  for (size_t i = 0; i < pixel_count*4; i+=4) 
  {
    memcpy(pixels+i, &color, 4);
  }
}

_B:
LFB1:
	movl	_height, %eax
	movl	_width, %edx
	imull	%eax, %edx
	xorl	%eax, %eax
	movl	_color, %ecx
	sall	$2, %edx
	je	L15
L19:
	movl	%ecx, _pixels(%eax)
	addl	$4, %eax
	cmpl	%edx, %eax
	jb	L19
L15:
	ret
I would expect them to be very similar in execution time. The inner loops [L6 for A and L19 for B] are basically identical. A does some extra work at the end of each row, but it shouldn't matter much overall.

If you wanted to make it even faster, the next thing I would do is start unrolling the loops. In both versions, each pass through the inner loop does one pixel's worth of useful work and one add, compare, and branch. You can do better than that by setting more than one pixel per loop iteration.

Say you have 1024 pixels to set. You can split it into two loops, one that sets 100 pixels at each iteration that runs 10 times to cover 1000 pixels and then one that sets one per iteration that runs 24 times. The loop overhead will be a much smaller percentage of the total time. Performance will increase as the amount set per loop increases up to the point where the loop no longer fits in the CPU's instruction cache.

Of course if you know the array sizes at compile time, the most efficient version of all is something with no loops either using rep instructions or just a bunch of mov's in a row.


And none of this will ever matter in real code unless you're doing stuff like writing image filters.

Praseodymi
Aug 26, 2010

This is all from memory as I'm currently stood outside the New Look changing rooms, so sorry if it's incorrect but I hope you'll get the gist of it.
Basically, we were given a pointer to the first pixel of the screen, and each pixel has four bytes, RGB and alpha. the fastest method was doing the two nested for loops with y at the top and x inside, and then doing a memcpy to at screenPointer + 4 * (x + y * screenWidth) of the 4 values we wanted to use for that pixel. Seeing as it was one contiguous block of memory and the x and y values were just for readability I'd just done
code:
for( int i = 0; i < screeWidth * screenHeight *4; i += 4)
{ 
memcpy(*the next 4 values)
} 
Seeing how this was avoiding doing as much maths for every pixel I thought this would be faster than the other method above but it wasn't.

If this still doesn't make sense I can look at the actual code when I get home.

nielsm
Jun 1, 2009



Praseodymi posted:

This is all from memory as I'm currently stood outside the New Look changing rooms, so sorry if it's incorrect but I hope you'll get the gist of it.

If that's how the actual loop condition was written, yeah I'm not too puzzled if it's slower.
Keep in mind that the loop condition (here, i < screeWidth * screenHeight *4) is evaluated for every iteration. The compiler might not be able to optimise the right-hand side of the < to a constant expression for whatever reason. So you are still doing multiplications for each pixel here, and it's in a comparison operation, not memory address operation.

As far as I can tell from the disassembly Foxfire_ posted, the A version actually compiled to something similar to what I wrote as the hybrid A+B, in that it calculates a row start pointer before each inner loop and then increments that as a "current pixel" pointer inside the inner loop.
The really important part is that it uses the x86 addressing modes to do the multiplications for pointer calculation, it doesn't use an actual multiplication instruction even once. The addressing modes are faster than arithmetic multiplication, but have a few limitations.

Meanwhile, the disassembly for the B version does a single (arithmetic) multiplication, outside the loop, and then only does incrementing of a "current pixel index" inside the loop. That should be fast, even more so if the loop is unrolled. Same for the A version disassembly.

The A version is much longer since it ends up using several more registers, which mean the compiler had to add a prologue and epilogue to save those on the stack first.
But both of those disassebles are of course the result of an optimising compilation, a naive compilation would probably have looked much different.

Returning back to your version, I think it's slow because either you compiled it without optimisations, or otherwise the optimiser couldn't figure out what you were doing in the loop condition and ended up doing arithmetic multiplications every iteration.

Praseodymi
Aug 26, 2010

Hmm, that's a good point actually, I think they were both compiled using Visual Studio's debug settings. I'll try it in release and see the difference, thanks.

Coca Koala
Nov 28, 2005

ongoing nowhere
College Slice
I'm not that great at C; is there some way I can declare a struct to be global such that multiple threads see the same struct?

I'm trying to implement a mutex with test_and_set. I can get the mutual exclusion pretty easily, but I'm having trouble guaranteeing fairness. The mutex has a simple queue which is basically an array plus a size counter, a head position, and a tail position (and of course the array is protected by a spinlock using test and set). Basically, if thread A tries to get the mutex while thread B is currently using the mutex, then thread A will stick itself in the queue by adding itself to array[tail], increment tail, and then increment the size. Within the context of thread A, it seems like that works, A goes in the queue, and the queue size goes up.

However, when thread B finishes, it still has a queue size of 0; even though it should ostensibly be accessing the same queue, it's not seeing the same size.

I've tried declaring all the attributes of the queue (size, head, tail) to be volatile, and it still doesn't seem to work. Threads should be sharing memory; can anybody explain why each thread has an inconsistent view of the same struct?

Here's my queue struct, for reference

code:
struct thread_queue {
  int max_size;
  volatile int current_size;
  volatile int head;
  volatile int tail;
  thread_t* elements;
  volatile unsigned long elements_lock;
};

typedef struct thread_queue thread_queue_t;
and the enqueue method
code:
int thread_queue_enqueue(thread_queue_t queue, thread_t t)
{
   while (test_and_set(&queue.elements_lock)));
   if (queue.current_size == queue.max_size)
   {
      printf("queue is full\n");
      return -1;
   }
   else
   {
      queue.current_size += 1;
      queue.elements[queue.tail] = t;
      queue.tail += 1;
      if (queue.tail == queue.max_size)
      { queue.tail = 0;}
   }
   queue.elements_lock = 0;
   return 0;
}

int thread_queue_size(thread_queue_t queue)
{
   return queue.current_size;
}
Any advice? I'm pretty sure this is the code that's relevant, but if you want info on the mutex struct or anything, I can provide that as well.

robostac
Sep 23, 2009
You are passing the struct by value, so you are only changing a local copy of it. You need to pass a pointer instead.

Coca Koala
Nov 28, 2005

ongoing nowhere
College Slice
That is a very simple explanation for what I thought was gonna be a really complicated problem. Thanks; like I said, I'm really not that great at C.

Delta-Wye
Sep 29, 2005
I've found myself digging into a lot of large projects lately, and have found my current toolset pretty inefficient for exploring a big unknown body of code. I have the function I'm interested in which includes a bunch of objects of a class I'm not familiar with, which have a bunch of member objects I'm also not familiar with, all having their various member functions called.

I've pretty much always done my editing in vi and that works great when I know what I'm looking at and which file contains what I need. I've experimented with loading the project up on code::blocks so I can click on something and "go to definition" and that works, but I still suspect there is a better option.

Is there any recommended plugins for vi that could help? A better program all together?

Delta-Wye fucked around with this message at 17:58 on Oct 21, 2013

Dicky B
Mar 23, 2004

YouCompleteMe provides go-to-declaration/go-to-definition operations but I've found its reliability a bit sporadic. You may have better luck than me.

ctz
Feb 6, 2003

Coca Koala posted:

I'm really not that great at C.

The best thing to do is add threads. Multithreading is easy and is an excellent thing for beginners to tackle.

Foxfire_
Nov 8, 2010

Coca Koala posted:

Mutex stuff

This is still going to be wrong on multiprocessors. Nothing guarantees that all the threads see memory accesses in the same order.

I don't think there's any portable way to reimplement mutexes. You need fence instructions for whatever your processor you're on or a guarantee that it doesn't need them.

Dren
Jan 5, 2001

Pillbug
Is there a word for binaries that are just linked together libraries and do not contain any of their own symbols?

coffeetable
Feb 5, 2006

TELL ME AGAIN HOW GREAT BRITAIN WOULD BE IF IT WAS RULED BY THE MERCILESS JACKBOOT OF PRINCE CHARLES

YES I DO TALK TO PLANTS ACTUALLY

The Little Book of Semaphores. The C chapter starts on p255 with a mutex example, though you'd do well to read Chapters 1-3 first.

Doctor w-rw-rw-
Jun 24, 2008

Dren posted:

Is there a word for binaries that are just linked together libraries and do not contain any of their own symbols?

...Isn't "binaries" sufficient? And what do you mean by "own"? What kind of library has no symbols?

Coca Koala
Nov 28, 2005

ongoing nowhere
College Slice

coffeetable posted:

The Little Book of Semaphores. The C chapter starts on p255 with a mutex example, though you'd do well to read Chapters 1-3 first.

This looks like a really helpful resource; thanks for bringing my attention to it!

Dren
Jan 5, 2001

Pillbug

Doctor w-rw-rw- posted:

...Isn't "binaries" sufficient? And what do you mean by "own"? What kind of library has no symbols?

It's a binary that consists solely of linked together shared objects.

The real issue is that I am going to have to explain why certain binaries don't show up as having a Stack Canary when checksec.sh is run on them.

If a binary doesn't link at least one object file it won't have any symbols that actually got compiled with stack canaries (-fstack-protector-all) and thus will be reported as not having a stack canary on the test. I'd like to get a better understanding of what's really going on so that I can allay the fears of people who run the test but have no clue what it's doing.

I think I've found the explanation for the code that does exist in the binary: http://www.delorie.com/gnu/docs/gcc/gccint_149.html

pseudorandom name
May 6, 2007

The question you meant to ask "Is there a word for object files that contain no executable code?"

And even that isn't exactly right, because there's functions that won't have canaries because they don't need them. That script is rather dumb.

Dren
Jan 5, 2001

Pillbug

pseudorandom name posted:

The question you meant to ask "Is there a word for object files that contain no executable code?"

And even that isn't exactly right, because there's functions that won't have canaries because they don't need them. That script is rather dumb.

The binary does contain executable code. It's boilerplate code that gcc sticks in there for running constructors when the program starts. The way I'm thinking I will talk about these files is by saying they "contain nothing but compiler supplied boilerplate code".

I totally agree with you about the dumbness of that script.

pseudorandom name
May 6, 2007

There's plenty of non-boilerplate user-created functions that don't need canaries and won't have them.

Dren
Jan 5, 2001

Pillbug

pseudorandom name posted:

There's plenty of non-boilerplate user-created functions that don't need canaries and won't have them.

Thanks, I will also include some information about other ways to compile something with -fstack-protector-all and fail the test.

edit: actually, I can't seem to find any. Even a trivial object file gets a canary with -fstack-protector-all (when it doesn't with -fstack-protector)

C code:
int dumbfunc()
{
  return 0;
}
code:
dren@computer ~/projects/nocanary$ gcc -fstack-protector-all -c nocanary.c
dren@computer ~/projects/nocanary$ checksec.sh --file nocanary.o 
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
No RELRO        Canary found      NX enabled    Not an ELF file   No RPATH   No RUNPATH   nocanary.o
dren@computer ~/projects/nocanary$ gcc -fstack-protector -c nocanary.c 
dren@computer ~/projects/nocanary$ checksec.sh --file nocanary.o 
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
No RELRO        No canary found   NX enabled    Not an ELF file   No RPATH   No RUNPATH   nocanary.o

Dren fucked around with this message at 18:43 on Oct 23, 2013

pseudorandom name
May 6, 2007

Oh, I missed that you're using -fstack-protector-all. That might actually cover everything that isn't compiler generated.

You may want to mention something about object files that contain only data, though, just to cover all bases.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
Coverity tells me that the following code results in an out-of-bounds array read:
code:
std::vector<std::string> vec;
vec.insert(vec.begin(), "");
Is it just being dumb, or is there some reason this would be unsafe other than a libc++ bug?

Adbot
ADBOT LOVES YOU

hooah
Feb 6, 2006
WTF?
I'm having trouble figuring out how to erase from a map. I have a function that takes in a map<string, string> and is supposed to copy certain elements to an empty map of the same type, then erase those elements from the first map:
code:
map<string, string> start_and_stops(map<string, string> &codon_map){
	map<string, string> start_stops;
	for (auto it : codon_map){
		if (it.second == "START" || it.second == "STOP"){
			start_stops[it.first] = it.second;
			codon_map.erase(it.first);
		}
	}
	return start_stops;
}
This compiles fine, but unless I comment out codon_map.erase(it.first);, I get a "Debug Assertion Failed" runtime error that "map/set iterator not incrementable". What's going wrong?

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