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
guenter
Dec 24, 2003
All I want out of life is to be a monkey of moderate intelligence who wears a suit. That's why I've decided to transfer to business school!

Avenging Dentist posted:

You're trying to generalize waaaay too much there. Why not just, you know, make a specialized Ship class inheriting from Entity and load stuff in from a config file?

The approach is fairly well accepted, avoiding concrete inheritance trees that is. I've been experimenting with it since I saw Scott Bilas' GDC presentation. http://www.drizzle.com/~scottb/gdc/game-objects_files/frame.htm

I'm working on a (much simplified) version of what he referred to as the ContentDB, I suppose.

Adbot
ADBOT LOVES YOU

Avenging Dentist
Oct 1, 2005

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

guenter posted:

The approach is fairly well accepted, avoiding concrete inheritance trees that is. I've been experimenting with it since I saw Scott Bilas' GDC presentation. http://www.drizzle.com/~scottb/gdc/game-objects_files/frame.htm

Not the way you're doing it. For god's sake, you're trying to factor world transforms out of in-game entities.

You'll notice that even in his presentation, Bilas' C++ class list (slide 18) is considerably more concrete than yours. Besides that, Gas Powered Games has 30-some people (not all programmers, obviously) with prior experience in game development. The presentation basically amounts to "hurf durf we use scripting languages" anyway. Everyone uses scripting languages in games these days.

Also, you seem to have missed the presentation's most fundamental point: C++ isn't the appropriate language for dynamically throwing stuff together like that. That's why modern game engines use scripting languages and create bindings in the scripting environment for their high-performance C++ classes.

Avenging Dentist fucked around with this message at 23:14 on Oct 8, 2008

pseudopresence
Mar 3, 2005

I want to get online...
I need a computer!
Just throwing some Lua on top of your C++ engine and exposing some classes isn't the same as a component-based game entity system; in fact, the two issues are pretty much orthogonal. The component-based approach is about creating units of game entity behaviour that can be composed on the fly. Then your designer (or more likely a programmer because wah wah it's too hard) copy-pastes an XML file for "red switches that go woosh" and makes a new "green switch that goes swish" and pops a few into the level without having to touch any actual code. Scripting languages can be used in combination with components in various ways but it's a completely different aspect of the design.

Avenging Dentist
Oct 1, 2005

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

Fib posted:

Just throwing some Lua on top of your C++ engine and exposing some classes isn't the same as a component-based game entity system; in fact, the two issues are pretty much orthogonal.

That's not what I was asserting at all? :confused: A component-based approach is ill-suited to a language like C++ (and you wouldn't want to do all the composition in C++ anyway due to link times, etc), and really sees the most benefit from a scripting language of some kind. Maybe in game development, components are zazzy and new, but they're really not all that exciting. :pwn:

That's all ancillary to the main point, which is: not every single thing needs to be its own separate component.

pseudopresence
Mar 3, 2005

I want to get online...
I need a computer!

Avenging Dentist posted:

That's not what I was asserting at all? :confused: A component-based approach is ill-suited to a language like C++ (and you wouldn't want to do all the composition in C++ anyway due to link times, etc), and really sees the most benefit from a scripting language of some kind.
But he was talking about changing that do use a definition in an external file of some kind, which is something you'd want to do. And that file doesn't have to be a script, it can be a declarative description of the component in XML or whatever.

Avenging Dentist posted:

Maybe in game development, components are zazzy and new, but they're really not all that exciting. :pwn:
They are new again every few months when someone posts about them on some industry mailing list, it is all they talk about :(.

Avenging Dentist posted:

That's all ancillary to the main point, which is: not every single thing needs to be its own separate component.

You could probably mash a few of those together and call them "Common" or "Actor" but it wouldn't keep me awake at night.

Avenging Dentist
Oct 1, 2005

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

Fib posted:

You could probably mash a few of those together and call them "Common" or "Actor" but it wouldn't keep me awake at night.

Well, he was specifically worried about the complexity of declaring all those components, so using fewer of them seems like a good solution for that particular issue.

Fib posted:

They are new again every few months when someone posts about them on some industry mailing list, it is all they talk about :(.

That's because game programmers just do whatever someone else said was a good idea years ago. :pwn:

Avenging Dentist fucked around with this message at 00:03 on Oct 9, 2008

guenter
Dec 24, 2003
All I want out of life is to be a monkey of moderate intelligence who wears a suit. That's why I've decided to transfer to business school!

Avenging Dentist posted:

Not the way you're doing it. For god's sake, you're trying to factor world transforms out of in-game entities.

You'll notice that even in his presentation, Bilas' C++ class list (slide 18) is considerably more concrete than yours. Besides that, Gas Powered Games has 30-some people (not all programmers, obviously) with prior experience in game development. The presentation basically amounts to "hurf durf we use scripting languages" anyway. Everyone uses scripting languages in games these days.

Also, you seem to have missed the presentation's most fundamental point: C++ isn't the appropriate language for dynamically throwing stuff together like that. That's why modern game engines use scripting languages and create bindings in the scripting environment for their high-performance C++ classes.

WorldTransform may be an unfortunate name. It's not as if I just wrapped a single matrix in a component. WorldTransform also serves as a node in a separate transform graph so I wouldn't want to merge it into Entity or anything.

I don't see that much difference in the granularity of our component selection. I probably have some that could be in script instead of in the codebase though. I realize what amounts to preferring composition over inheritance isn't some new thing but I find static class hiearchies are particularly unsuited to game development.

I'm not sure the point of the presentation is "C++ is bad for throwing stuff together, use a scripting language" but the fact is hardly lost on me. A data-driven system has been a goal since the beginning and that's what I'm grappling with now. Ideally nothing game-specific will be in C++ when I'm done, it will all be in python :).

Maybe I could work on being able to build entities in script instead of being able to load entities from some kind of schema? It still seems like the latter would be needed though. The end goal is to be able to be able to build entire scenarios/levels in script so maybe I should just ask how to approach that?

Avenging Dentist
Oct 1, 2005

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

guenter posted:

Ideally nothing game-specific will be in C++ when I'm done, it will all be in python :).

Not even Unreal Engine does this (there's a reason multiple game studios have dropped UE3 mid-development). The trick to making a decent game engine decent software is to generalize as little as possible. Otherwise, you end up with an overcomplicated mess where your scripting environment is no simpler than direct API calls in C++, only you have the added overhead of the interpreter.

guenter posted:

I don't see that much difference in the granularity of our component selection. I probably have some that could be in script instead of in the codebase though.

I'd say you have roughly two components for every one covered in the presentation.

Avenging Dentist fucked around with this message at 03:03 on Oct 9, 2008

The Red Baron
Jan 10, 2005

Thanks, TTS, I was hoping you'd reply! Great advice as usual

quote:

instead of using template template parameters, I'd recommend MPL-style metaclasses and lambdas instead. This has a few benefits. For one, MPL has many more tools for manipulating and working with metaclasses than raw templates. It also means that you may then use Boost.Parameter to make your factory templates more self-documenting and allows people to specify the arguments in any order and still implicitly get all the appropriate defaults for the unspecified parameters (such as overriding the associative container but leaving the constructor parameters implicitly default, or just changing the error policy, etc.).
This sounds really interesting, but I'm honestly a bit unsure of how to go about doing it. Do you mean that instead of using
code:
template <typename Key, class Value>
struct std_map_adapter
{
  typedef std::map<Key, Value> type;
};
I would use something like this:
code:
struct std_map_adapter
{
  template <typename Key, class Value>
  struct apply
  {
    typedef std::map<Key, Value> type;
  }
};
or am I way off? I started getting into the MPL pretty recently, and haven't really looked much at Boost.Parameter, so I'm still not entirely steady on a lot of their details.

quote:

A less subjective decision I'm a little concerned with is that auto_ptr is used. When working with a generic factory template, I wouldn't expect this since it implies that the objects are allocated and deallocated using new and delete. In the style of C++, that may be overly restrictive, especially in the context of a factory. To be generic, I would avoid this type of assumption and instead either have a template parameter of the factory be a deleter (defaulting to use delete) and have the create function return an auto_ptr-like smart pointer but with an attached deleter, or don't add a template parameter and instead delegate all responsibility to the user entirely.
A very good point. The usage of auto_ptr is mostly from me taking Exceptional C++ a bit too literally on some of its advice.

quote:

map-style creation, no need for argument forwarding, function-style template parameters et al.
Awesome stuff! I'll rewrite the code to incorporate these suggestions as soon as possible :)

quote:

If you really wanted to, you could make the parameter a function object type instead of a function type and use that as the mapped type in the internal associative sequence, and that would even allow the user to override how the internal function object is stored, making your template about as generic as it could be, but that's probably overstepping the needs of the common user.
Would it be a good move to keep this as an optional template parameter for factory itself?

ShinAli
May 2, 2003

The Kid better watch his step.
Got a quick question about pointers in C.

Right now I got a struct with a growing character array which would contain multiple strings. Every time I run out of space (when adding strings), I realloc the struct. This keeps it in one memory block.

I also have a string (or character pointer) array which the elements point to individual strings in the character array of the struct. The obvious problem being is that when the character array struct gets reallocated, the pointers in the string array get outdated.

To update them, I search the outdated string array for the base pointer of the old struct (I just compare all pointers via ptr1 < ptr2 in a loop and which ever is the smallest, I figure is the base pointer). The idea I have is to subtract the old base pointer with every char pointer in the array, then add the base pointer of the realloc'ed struct character array to every element.

I'm not sure if I'm allowed to do that, though. Do I cast the pointers to some other type, do what I need to do, and cast it back to a pointer?

aViR
Aug 6, 2004

ShinAli posted:

Got a quick question about pointers in C.

Right now I got a struct with a growing character array which would contain multiple strings. Every time I run out of space (when adding strings), I realloc the struct. This keeps it in one memory block.

I also have a string (or character pointer) array which the elements point to individual strings in the character array of the struct. The obvious problem being is that when the character array struct gets reallocated, the pointers in the string array get outdated.

To update them, I search the outdated string array for the base pointer of the old struct (I just compare all pointers via ptr1 < ptr2 in a loop and which ever is the smallest, I figure is the base pointer). The idea I have is to subtract the old base pointer with every char pointer in the array, then add the base pointer of the realloc'ed struct character array to every element.

I'm not sure if I'm allowed to do that, though. Do I cast the pointers to some other type, do what I need to do, and cast it back to a pointer?

That approach should work, and yes you would cast the pointers to unsigned integers, do your math, and cast back, e.g. (untested):
code:
newStruct.strings[i] = (char*)((unsigned int)oldStruct.strings[i] - (unsigned int)oldstruct.hugeCharArray + (unsigned int)newStruct.hugeCharArray);
note: this assumes that int is the same size as char* on your architecture.

It might be a lot easier to keep an array of integers where each integer is the offset in the char array of the first character it points to. Then, you don't need to rebuild the array of pointers every time you re-alloc the struct. To reference a particular string, just do something like
code:
&struct.hugeCharArray[struct.arrayOfOffsets[index]]
instead of
code:
struct.arrayOfStrings[index]
You could even write a macro to make it less ugly:
code:
#define nthstring(s,n) &(s).hugeCharArray[(s).arrayOfOffsets[(n)]]

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

ShinAli posted:

I'm not sure if I'm allowed to do that, though. Do I cast the pointers to some other type, do what I need to do, and cast it back to a pointer?

Your original proposal sounds like perfectly correct and portable C. But why on earth do you need to allocate strings in a consecutive block like that?

Scaevolus
Apr 16, 2007

ShinAli posted:

Got a quick question about pointers in C.

Right now I got a struct with a growing character array which would contain multiple strings. Every time I run out of space (when adding strings), I realloc the struct. This keeps it in one memory block.

I also have a string (or character pointer) array which the elements point to individual strings in the character array of the struct. The obvious problem being is that when the character array struct gets reallocated, the pointers in the string array get outdated.

To update them, I search the outdated string array for the base pointer of the old struct (I just compare all pointers via ptr1 < ptr2 in a loop and which ever is the smallest, I figure is the base pointer). The idea I have is to subtract the old base pointer with every char pointer in the array, then add the base pointer of the realloc'ed struct character array to every element.

I'm not sure if I'm allowed to do that, though. Do I cast the pointers to some other type, do what I need to do, and cast it back to a pointer?
This sounds a lot like premature optimization.

Vanadium
Jan 8, 2005

aViR posted:

That approach should work, and yes you would cast the pointers to unsigned integers, do your math, and cast back

I am pretty sure it is not defined behaviour to dereference pointers you obtain by casting an integer, unless you got the integer by casting a pointer in the first place. Just use pointer arithmetic directly.

DontMockMySmock
Aug 9, 2008

I got this title for the dumbest fucking possible take on sea shanties. Specifically, I derailed the meme thread because sailors in the 18th century weren't woke enough for me, and you shouldn't sing sea shanties. In fact, don't have any fun ever.

rjmccall posted:

Okay, in that case you can do this really efficiently: fopen the file, fseek to the offset (N*x+y)*K*8, fread K*8 bytes into an appropriately-sized buffer, and fclose. You probably want to disable library-level buffering on the FILE*.

Just in case you've never used fread-like APIs before: fread can return to you with an incomplete result, so you'll need to loop until you've read all K entries. Of course, if you don't need to materialize the entire K-vector at once, you can just read it in bits and pieces and process the data as it's read.

I'm not sure I understand that entirely, but it seems like you think the K values I am trying to read are next to each other in the file, which they are not. They are separated by N*N-1 other data points, or something like that. Also, this needs to be done several thousand times for different x and y values.
Finally, and I know this is a dumb question, but can you explain to me the syntax of fread? I looked it up online and the explanations I found were much lacking. I don't know what all the arguments are supposed to be.

Edit: To clarify, you WAY overestimate my C knowledge. I am not a CS major. For example, the phrase "disable the library-level buffering on the FILE*" makes absolutely no sense to me.

DontMockMySmock fucked around with this message at 18:31 on Oct 9, 2008

Mikey-San
Nov 3, 2005

I'm Edith Head!

DontMockMySmock posted:

can you explain to me the syntax of fread? I looked it up online and the explanations I found were much lacking. I don't know what all the arguments are supposed to be.

From the fread docs:

quote:

size_t
fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);

Description

The function fread() reads nitems objects, each size bytes long, from the stream pointed to by stream, storing them at the location given by ptr.

I'll attempt to break these down for you. There's a lot of stuff here. Also, I'm going to do them in an order that may make more sense to you.

void *restrict ptr

The most important thing to know here is that this first |ptr| argument is just a pointer to a data buffer. It can be anything you want. A buffer of ints, chars, YourSpecialDataType, anything. That's why it's a void pointer. Pass a pointer to any block of memory you've allocated.[1]

The "restrict" keyword here is a hint to the compiler that says, "I am guaranteeing to you, the compiler, that the data being referenced by this pointer is not referenced by any OTHER pointers. You are free to perform kickass optimizations that make this assumption."

http://developers.sun.com/solaris/articles/cc_restrict.html

FILE *restrict stream

This is just a pointer to a file you want to read data from. That's all. You can obtain this FILE pointer with fopen().

This argument utilizes the "restrict" keyword as well, but you know what that means now, so it's no big deal.

size_t nitems

This is less complicated than the man page makes it out to be. You just want to read a certain number of "things" in your file, right? That's all this number is. Remember, to the computer, it's a stream of bytes with no order or meaning; to YOU, the file is a conceptual pile of stuff. You want to read |nitems| things from your file.

But all this does is tell the computer how many things to read. A single "thing" might be 5 bytes long, it might be 1 byte. Unless you tell fread() how large each thing is, it can't know what data to read. So:

size_t size

This tells fread() how large each thing you want to read is. If you want to read 10 bytes from the file, one byte at a time, you would pass 10 for |nitems| and 1 for |size| because you're reading 10 things that are each 1 byte large. If you wanted to read 500 bytes from the file, 10 bytes at a time, you would pass 50 for |nitems| and 10 for |size|.

[1] The |ptr| data buffer must be large enough to hold the amount of data you tell fread() to read. If you're reading 10 pieces of data that are each 2 bytes long, you need a buffer that can hold 20 bytes of data at a time.

edit: an example might be useful

Here's an example of reading a text file and printing its contents to the console.

code:
#define BUFFER_SIZE 10
#define ITEM_SIZE 1

const char *filePath = "/path/to/file.txt"; // this is the path of the file we want to read
FILE *file; // a pointer to the stream of bytes that represent our file

// we want space enough to hold BUFFER_SIZE bytes, plus one byte for
// the NUL string terminator (since we're printing strings)
char buf[BUFFER_SIZE + 1];

// fread() returns how many items it read, which is important for us,
// because we can use that information to know where to place the NUL terminator
int n;

// open the file for reading
file = fopen(filePath, "r");
if (file == NULL)
{
	// fopen() returns NULL if it fails to open the file. oh poo poo! bail!
	return 1;
}

// 0. set n to the number of items fread() was able to read. if this number is 0, we're done.
// 1. pass in our data buffer for the first argument. this is where fread() will place the data it sucks in from the file.
// 2. each item we read will be ITEM_SIZE bytes long (which is just 1 byte long, the size of a char).
// 3. we're going to read BUFFER_SIZE items, which is 10. read 10 items that are each
// ITEM_SIZE bytes long. for us, this means we'll read 10 bytes of data at a time.
// 4. read this data from |file|.
while ((n = fread(buf, ITEM_SIZE, CHAR_BUFFER, file)) != 0)
{
	// right now, the |buf| data buffer contains n * ITEM_SIZE bytes of data (10 bytes).
	// we can do whatever we want with this. let's just say it's a text file and
	// we're just going to print it to the console. that means we have to add a
	// NUL terminator to the end of the string we're about to print.
	
	buf[n * ITEM_SIZE] = 0; // n conveniently tells us where to place the NUL terminator.
	printf("%s", buf); // hurf durf print string
}

Mikey-San fucked around with this message at 20:23 on Oct 9, 2008

digibawb
Dec 15, 2004
got moo?

aViR posted:

That approach should work, and yes you would cast the pointers to unsigned integers, do your math, and cast back, e.g. (untested):
code:
newStruct.strings[i] = (char*)((unsigned int)oldStruct.strings[i] - (unsigned int)oldstruct.hugeCharArray + (unsigned int)newStruct.hugeCharArray);
note: this assumes that int is the same size as char* on your architecture.

There's no need for any of those casts.

Cross_
Aug 22, 2008

ShinAli posted:

Right now I got a struct with a growing character array which would contain multiple strings. Every time I run out of space (when adding strings), I realloc the struct. This keeps it in one memory block.
Is there a good reason why you want to keep them in one memory chunk?

quote:

The idea I have is to subtract the old base pointer with every char pointer in the array, then add the base pointer of the realloc'ed struct character array to every element.
That would work- it's probably easier and more reliable to only maintain a relative offset into the memory chunk instead of absolute addresses.
code:
char *lotsOfStrings=malloc( 200 );
strcpy( lotsOfStrings+100, "Hello SA!")
unsigned int someStringOffset1=100;

printf("%s", lotsOfStrings+someStringOffset1 );
lotsOfStrings= realloc( lotsOfStrings, 300);
printf("Unchanged: %s", lotsOfStrings+someStringOffset1 );

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

DontMockMySmock posted:

I'm not sure I understand that entirely, but it seems like you think the K values I am trying to read are next to each other in the file, which they are not. They are separated by N*N-1 other data points, or something like that.

Ah, okay. I think we talked past each other a bit there.

DontMockMySmock posted:

Also, this needs to be done several thousand times for different x and y values.

That radically changes the problem. I was treating your question as follows: "I have a file which acts as a sort of database of matrix data, and I want to extract a small amount of information from it." It sounds more like you're trying to do a matrix "rotation", i.e. transforming a sequence of K NxN matrices into an NxN matrix of K-vectors. This will perform much better if you process your file sequentially rather than trying to extract each vector individually.

What you really want is something like this (assuming I'm understanding your matrix major order):

code:
double output[][N][K] = malloc(N*N*K*sizeof(double));
for (int m = 0; m < K; ++m) {
  for (int x = 0; x < N; ++x) {
    for (int y = 0; y < N; ++y) {
      output[x][y][m] = read_next_double();
    }
  }
}
(Note that this code assumes that N and K are compile-time constants, i.e. defined using #define N 26, not const int N = 26;)

This code strides over memory wastefully, but that's way better than striding over disk wastefully.

DontMockMySmock
Aug 9, 2008

I got this title for the dumbest fucking possible take on sea shanties. Specifically, I derailed the meme thread because sailors in the 18th century weren't woke enough for me, and you shouldn't sing sea shanties. In fact, don't have any fun ever.
I'm still not sure that's the fastest way to do it, since I am not going to need the data sequentially, I will be sampling each K-size matrix at random as part of an algorithm. Any thoughts?

(Thanks for all the help, by the way).

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

DontMockMySmock posted:

I'm still not sure that's the fastest way to do it, since I am not going to need the data sequentially, I will be sampling each K-size matrix at random as part of an algorithm. Any thoughts?

What do you mean by "k-size matrix"? I've been assuming that you need the entire k-vector at a particular (x,y), and that your sampling process is looking at a subset of the possible (x,y)-coordinates. Since your vectors are not compact on disk, you will be touching many of the file's blocks, even if you only end up needing a very small proportion of the actual bytes from each block. Now, disks are much faster at reading sequential blocks than they are at reading randomly-accessed blocks, and competent filesystems try to lay files out to make sequential access faster. Therefore, it's quite possible that you will find it faster to read in the entire file than to try to avoid reading the parts you don't need.

This all assumes that it's actually possible to read the entire file into memory, and of course it might be too large for that.

Things you can try if you're worried about reading in the entire file:
  • If your algorithm allows you to precompute your sampling coordinates, you can just scan over the file once and selectively materialize exactly the k-vectors you need. You might be able to skip some blocks this way.
  • If the file's small enough to fit into the memory space of your machine, you can try mmapping it. That won't magically make your disk-access patterns more efficient, but it will likely make better use of the disk cache if you're still using the random-access patterns.
  • If you might need to run this computation many times on the same file, you might consider pre-processing it into a new file which records the k-vectors compactly.
  • Similarly, if you have control over the production of the original file, you might want to consider altering it to place the k-vectors sequentially. Of course, that depends on the efficiency needs of the producer and any other consumers out there.

Whilst farting I
Apr 25, 2006

I need to alphabetize a two dimensional string vector by the first column. An excerpt looks like this

Alan # Smithee # 45 # #
Bob # Smith # 29 # #
Cindy # Smith # 23 # #
David # Smith # 34 # #
Edward # Wood # 56 # #
Allie # Eric # 45 # #
Bob # Clark # 58 # #

I can read it in, ask it to output every row with the first name "Bob" and it works just fine.

I would just use sort after it is read in, but the file is massive, and every new row read in is supposed to be inserted alphabetically. And it is supposed to be done using an iterator. It should look something like this after.

Alan # Smithee # 45 # #
Allie # Eric # 45 # #
Bob # Clark # 58 # #
Bob # Smith # 29 # #
Cindy # Smith # 23 # #
David # Smith # 34 # #
Edward # Wood # 56 # #

Here is what my old code looked like that read them in okay, but didn't alphabetize them (sorry if any of the spacing is weird, I write in Notepad++ and copying and pasting from that doesn't preserve the format well - it looks good in that).

code:
StringTable::StringTable(ifstream & infile)
{
   // Initiates the string vector that will represent the rows
   vector<string> vecRows;
   const string sep = "#";
   string s;

   // While the end of the file is not reached
   while (!infile.eof())
   {
        // If readAllItems returns true, that means what it just
        // read in was not the seperator and is part of the data for the row
        if (readAllItems(s, infile, sep))
        {
                // Pushes back the row one element with the data
                // that was just read in
                vecRows.push_back(s);
				
        } // end if

        // readAllItems read in the seperator, signifying the
        // end of the row
        else
        {
                // Pushes back on the rows, makes room for a new
                // one
                twoDimStrVec.push_back(vecRows);

                // Clears this instance of vecRows
                vecRows.clear();
				
        }  // end else
   } // end while
} // end StringTable constructor
But as of right now, whenever I try to alphabetize them, I get the first element at the very end of the otherwise-alphabetized list.

Allie # Eric # 45 # #
Bob # Clark # 58 # #
Bob # Smith # 29 # #
Cindy # Smith # 23 # #
David # Smith # 34 # #
Edward # Wood # 56 # #
Alan # Smithee # 45 # #

Here's what's causing that output.

code:
StringTable::StringTable(ifstream & infile)
{
    bool insertComplete;
    int i;
    const string sep = "#";
    string s;
    vector<string> vecRows;
    vector< vector <string> >::iterator tableItr;

    while (readAllItems(s, infile, sep))
    {
        i = 0;
        insertComplete = false;

        // Clears the row
        vecRows.clear();

        // Pushes back each individual element in the row
        do
        {
            vecRows.push_back(s);
        }
        while (readAllItems(s, infile, sep));

        // If the table is empty, just push back the first element to avoid
        // a seg fault
        if (twoDimStrVec.empty())
        {
            twoDimStrVec.push_back(vecRows);
        }
		
	// If it's not empty, sort it
        else
        {
		// Iterator begins where the beginning of the table is, traverses the entire twoDimStrVec.
		for (tableItr = twoDimStrVec.begin(); !insertComplete && tableItr != twoDimStrVec.end(); tableItr++)
		{
			if (tableItr == (twoDimStrVec.end() - 1))
			{
				twoDimStrVec.insert(tableItr,vecRows);
				insertComplete = true;
			}

			else if (vecRows[0] <= twoDimStrVec[i][0])
			{
				twoDimStrVec.insert(tableItr,vecRows);
				insertComplete = true;
			} 

			else
				i++;
					
		} // end for-loop
        } // end else
    } // end while loop
} // end constructor
In what way can I approach this where the first element won't show up as the last? I've tried inserting it, but then the entire 2d vector remains empty. I know it's that I'm pushing back the first row that's causing all of this, but because inserting it instead doesn't work, I'm lost. Thanks!

Whilst farting I fucked around with this message at 22:17 on Oct 10, 2008

floWenoL
Oct 23, 2002

Whilst farting I posted:

I need to alphabetize a two dimensional string vector by the first column. An excerpt looks like this

Why aren't you using std::set or at least std::sort?

Edit:
Why does your inner loop do the same thing (readAllItems) as your outer loop?

floWenoL fucked around with this message at 23:43 on Oct 10, 2008

awesmoe
Nov 30, 2005

Pillbug
I've been some of the best-practice textbooks out there and they strongly discourage macro use (for pretty sensible sounding reasons).
I was wondering if there was an accepted replacement for debug/instrumentation macros? Or if I've been lied to my whole professional life and there's no reason to do debugging as a macro in the first place.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

awesmoe posted:

I've been some of the best-practice textbooks out there and they strongly discourage macro use (for pretty sensible sounding reasons).
I was wondering if there was an accepted replacement for debug/instrumentation macros? Or if I've been lied to my whole professional life and there's no reason to do debugging as a macro in the first place.

Programming language style guides are every bit as full of sketchy folk wisdom and misguided over-prescriptions as, well, natural language style guides. There are lots of sensible uses for macros, and debugging and instrumentation are high among them. Moreover, they are often the only reasonable way of accomplishing things like, say, globally-scoped compile-time constants or basic compiler/platform portability. In an ideal world, many of these things would be accomplished by safer, more principled language features; but we do not live in such a world, at least inasmuch as we are writing code in C and C++.

Of course, there's a pretty long list of things you should not use macros for:
  • Do not use macros as a cheap form of inlining.
  • Do not use macros as a cheap form of polymorphism.
  • Do not use macros to "override" external declarations, unless you are absolutely forced to.
  • Do not use macros to implement your own private syntax.
  • etc.

But as long as you obey the principle of least surprise, you should be fine.

Cosmopolitan
Apr 20, 2007

Rard sele this wai -->
I'm working on an assignment for my C++ class (instructions here). I've got everything working so far, except the output for the maximum profit, its ticket cost and number of passengers.

I don't know how I would go about having the program collect that information. I'm thinking maybe it has to scan all the output, find the highest value in profit, and assign it, its ticket price, and number of passengers to their own variables. I'm not sure. Does anyone have any ideas?

Here's my code so far:
code:
int main()
{
	int passengers, minPassengers, maxPassengers;
	float ticketPrice, propTicketPrice, profit, overhead;
	char ans;

	do
	{
		// User defined variables.
		cout << "Enter the Proposed Initial Ticket Price: ";
		cin >> propTicketPrice;
			if (propTicketPrice < 0)
				propTicketPrice = propTicketPrice * (-1);

		cout << "\n\nEnter the Minimum Number of Passengers: ";
		cin >> minPassengers;
			if (minPassengers < 0)
				minPassengers = minPassengers * (-1);

		do
		{
		cout << "\n\nEnter the Maximum Number of Passengers: ";
		cin >> maxPassengers;
			if (maxPassengers <= minPassengers)
			{
				cout << "You entered the Maximum Number of Passengers as: " << maxPassengers;
				cout << "\nMaximum Number of Passengers cannot be equal to or less than Minimum Number of Passengers. Try again.";
			}
		}while(maxPassengers <= minPassengers);
		system("cls");

		// Calculations
		overhead = 2500.0;

		// Output.
		cout << fixed << showpoint << setprecision(2);
		cout << "Passengers" << "\t" << "Ticket" << "\t" << "Profit" << "\n";
		cout << "\t\t" << "Price" << "\n\n";
		for (passengers = minPassengers; passengers <= maxPassengers; passengers +=10)
		{
			ticketPrice = propTicketPrice - (((passengers - minPassengers) / 10) * .5f);
			profit = (passengers * ticketPrice) - overhead;

			cout << passengers << "\t\t" << ticketPrice << "\t" << profit << "\n\n";
		}


		
		cout << "Do you wish to go again? (y/n): ";
		cin >> ans;
		ans = (char) ans;
		ans = tolower(ans);

		system("cls");
	}while (ans == 'y');
	
	cout << "Press ANY key to continue...";
	_getch();
	return 0;
}

Whilst farting I
Apr 25, 2006

floWenoL posted:

Why aren't you using std::set or at least std::sort?

Edit:
Why does your inner loop do the same thing (readAllItems) as your outer loop?

I'm using STL, and the object is to insert each one into its correct alphabetical order as it happens.

The outer while loop is just a way of saying "while there is still data to be read from the file," I might change it to while (!.eof) like in the earlier example.

npn
Mar 7, 2006

rjmccall posted:

[*] Do not use macros to implement your own private syntax.
I occasionally implement foreach using macros since it saves a bunch of repetitious declaration/initialisations and, to my mind, makes it easier to see what is being done at a glance. Am I a bad person?

more falafel please
Feb 26, 2005

forums poster

Whilst farting I posted:

I'm using STL, and the object is to insert each one into its correct alphabetical order as it happens.

The outer while loop is just a way of saying "while there is still data to be read from the file," I might change it to while (!.eof) like in the earlier example.

I don't know how much of the STL you've been taught and are allowed to use, but it seems like a vector<vector<string> > isn't what you want here. A list of structs makes more sense to me:
code:
struct record
{
    std::string first_name;
    std::string last_name;
    int whatever_that_number_is;
};

std::list<record> listOfRecords;
much easier to do the inorder insertions

Incoherence
May 22, 2004

POYO AND TEAR

Anunnaki posted:

I'm working on an assignment for my C++ class (instructions here). I've got everything working so far, except the output for the maximum profit, its ticket cost and number of passengers.

I don't know how I would go about having the program collect that information. I'm thinking maybe it has to scan all the output, find the highest value in profit, and assign it, its ticket price, and number of passengers to their own variables. I'm not sure. Does anyone have any ideas?
You're calculating profit for each value of number of passengers/ticket cost already in your "Output" loop. Just keep a running maximum while you do that: start with your maximum so far being 0, and if the profit in a particular iteration of the loop is more than the maximum so far, save aside that maximum profit/number of passengers in a different set of variables.

(I'm not going to give you code because this is a class assignment and I'm not going to do ALL of your homework for you.)

Cosmopolitan
Apr 20, 2007

Rard sele this wai -->

Incoherence posted:

You're calculating profit for each value of number of passengers/ticket cost already in your "Output" loop. Just keep a running maximum while you do that: start with your maximum so far being 0, and if the profit in a particular iteration of the loop is more than the maximum so far, save aside that maximum profit/number of passengers in a different set of variables.

(I'm not going to give you code because this is a class assignment and I'm not going to do ALL of your homework for you.)

Ah, thank you very much! :D Just added the int "maxProfitPassengers", and floats "maxProfit, maxProfitPrice", and added this after my nested for:

code:
if (profit > maxProfit)
	{
		maxProfit = profit;
		maxProfitPassengers = passengers;
		maxProfitPrice = ticketPrice;
	}
and whala. The logic kills me every time on these things, hehe.

Whilst farting I
Apr 25, 2006

more falafel please posted:

I don't know how much of the STL you've been taught and are allowed to use, but it seems like a vector<vector<string> > isn't what you want here. A list of structs makes more sense to me:
code:
struct record
{
    std::string first_name;
    std::string last_name;
    int whatever_that_number_is;
};

std::list<record> listOfRecords;
much easier to do the inorder insertions

Well, it's supposed to be made into a vector of pointers to vectors of strings - and I have no idea how to declare that or how it'd effect the rest of my code. I tried declaring that like

vector<vector<string*> > *twoDimStrVec;

and now pretty much all of my code is broken. :psyduck:

I agree that structs would be much easier, but that's not what we're supposed to be doing and our book doesn't even have any information about vectors - and I can't find any information anywhere about a vector of pointers to vectors of strings. Our book doesn't even include vectors and in class we've not dealt with this, either.

That Turkey Story
Mar 30, 2003

The Red Baron posted:

Thanks, TTS, I was hoping you'd reply! Great advice as usual

This sounds really interesting, but I'm honestly a bit unsure of how to go about doing it. Do you mean that instead of using
code:
template <typename Key, class Value>
struct std_map_adapter
{
  typedef std::map<Key, Value> type;
};
I would use something like this:
code:
struct std_map_adapter
{
  template <typename Key, class Value>
  struct apply
  {
    typedef std::map<Key, Value> type;
  }
};
Yes.

The Red Baron posted:

Would it be a good move to keep this as an optional template parameter for factory itself?

I see two likely options:

Option one, which I think is what you're talking about, is making an additional optional parameter of the template be a metaclass which may take a function type as a parameter and yield a function object type. This means that anyone may override the internal function object type used by making a metaclass and passing it as an additional parameter. The plus side of this is that all of the parameters are fully orthogonal. A downside is that your template now takes yet another argument.

Option two is to keep the amount of template parameters the same as before but interpret the function type parameter as an overridden function object type only if a function type is not passed. In other words typename if_< is_function< your_parameter >, function< your_parameter >, your_parameter >::type. This makes it easy to specify a new function object type without requiring the user to make a metaclass and pass an additional argument, and keeps the overall amount of template parameters down to a minimum.

PnP Bios
Oct 24, 2005
optional; no images are allowed, only text
Hi, I'm working on some code for my OS class, and I'm using Fork and Pipe. When I pass this function a value of 2 or more for the process count it hangs. Am I missing something blatantly obvious?
code:
int metric(int *start_address, int count, int numThreads)
{
    int timeBase = time(NULL);
    int total = 0;
    int offset = count/numThreads;
    int ioPipes[2];
    pipe(ioPipes);
    for(int i = 0; i < numThreads; i += 1)
	{
		if (fork() == 0)
		{
			// child
			int qSum = 0;
			int val = 0;
			for (int j = i * offset; j < (i+1)* offset; j++)
			{
                val = start_address[j];
				qSum = qSum + (val * 3) + (val*val) + (6*~val);
			}
			write(ioPipes[1], &qSum, sizeof(int));
			exit(0);

		} else

		{
				// parent
			int rVal = 0;
			read(ioPipes[0], &rVal, sizeof(int));
			total += rVal;
		}
    }

    return  time(NULL) - timeBase;
}

PnP Bios
Oct 24, 2005
optional; no images are allowed, only text

PnP Bios posted:

Hi, I'm working on some code for my OS class, and I'm using Fork and Pipe. When I pass this function a value of 2 or more for the process count it hangs. Am I missing something blatantly obvious?
code:
Nevermind... apparently that code was fine, it was hanging on something in main.

The Red Baron
Jan 10, 2005

Whilst farting I posted:

Well, it's supposed to be made into a vector of pointers to vectors of strings - and I have no idea how to declare that or how it'd effect the rest of my code. I tried declaring that like

vector<vector<string*> > *twoDimStrVec;

and now pretty much all of my code is broken. :psyduck:

I agree that structs would be much easier, but that's not what we're supposed to be doing and our book doesn't even have any information about vectors - and I can't find any information anywhere about a vector of pointers to vectors of strings. Our book doesn't even include vectors and in class we've not dealt with this, either.
What you have there is a pointer to a vector containing vectors of string-pointers (try saying that quickly 3 times in a row). For a vector of pointers to vectors of strings, you'd use vector<vector<string>*>. For templated types like vector<type> where type is itself a templated type, try reading them "recursively" for each template parameter. Also, for pointers and references, keep in mind that they bind to the type that is on their left, so vector<string>* is a pointer to a vector of strings, while vector<string*> is a vector of string pointers.

Having the outer vector contain pointers to vectors of strings removes the potentially great overhead of copying every single inner vector and all their strings when the outer vector itself is copied (or resized). However, it requires you to either manually perform memory management to delete the inner vectors when they're no longer needed, use shared pointers rather than raw pointers or use a dedicated pointer container such as boost::ptr_vector.

quote:

Yes.
Gotcha

quote:

I see two likely options:

Option one, which I think is what you're talking about, is making an additional optional parameter of the template be a metaclass which may take a function type as a parameter and yield a function object type. This means that anyone may override the internal function object type used by making a metaclass and passing it as an additional parameter. The plus side of this is that all of the parameters are fully orthogonal. A downside is that your template now takes yet another argument.

Option two is to keep the amount of template parameters the same as before but interpret the function type parameter as an overridden function object type only if a function type is not passed. In other words typename if_< is_function< your_parameter >, function< your_parameter >, your_parameter >::type. This makes it easy to specify a new function object type without requiring the user to make a metaclass and pass an additional argument, and keeps the overall amount of template parameters down to a minimum.
Option two seems to be the most smooth one (dammit, why can't I come up with solutions like that <:mad:>), so I'll go with that.

I'm currently trying to get Boost.Parameter to work, but I'm having some problems getting it to accept function signature template parameters. It appears that it's instantiating an argument list type that contains functions such as
code:
template <class D>
reference get_default(D const&, mpl::false_) const
{
  return arg.value;
}
and since the argument is a function signature, this triggers a "function returns function" compiler error. Do you know if it's possible to have Boost.Parameter automatically wrap certain parameter types so that eg. instead of int*(int), it uses some_dummy_wrapper<int*(int)> instead? Obviously, I want to have this be completely transparent to the end-user.

I suppose it's possible to set the requirement that the factory's first template parameter always must be the function signature, avoiding Boost.Parameter for it, but that seems to kind of go against the whole point in using it in the first place.

edit: I suppose I could also temporarily wrap the template parameters in an MPL sequence, transform-wrap them based on is_function<> and then convert the sequence back to single parameter types before I let Boost.Parameter touch them at all :haw:

The Red Baron fucked around with this message at 21:18 on Oct 11, 2008

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

npn posted:

I occasionally implement foreach using macros since it saves a bunch of repetitious declaration/initialisations and, to my mind, makes it easier to see what is being done at a glance. Am I a bad person?

It's sketchy but not completely evil, at least if it avoids re-evaluating its arguments and doesn't internally hardcode knowledge about the ending condition. I wouldn't do it myself, though, and certainly not in code meant for wider reading. I've gotten pretty used to instantly deciphering for loops, so I'd probably spend longer looking at your macro and verifying that it does the sensible thing than I would just reading the for loop.

I agree that the typing is obnoxious.

Whilst farting I
Apr 25, 2006

The Red Baron posted:

What you have there is a pointer to a vector containing vectors of string-pointers (try saying that quickly 3 times in a row). For a vector of pointers to vectors of strings, you'd use vector<vector<string>*>. For templated types like vector<type> where type is itself a templated type, try reading them "recursively" for each template parameter. Also, for pointers and references, keep in mind that they bind to the type that is on their left, so vector<string>* is a pointer to a vector of strings, while vector<string*> is a vector of string pointers.

Having the outer vector contain pointers to vectors of strings removes the potentially great overhead of copying every single inner vector and all their strings when the outer vector itself is copied (or resized). However, it requires you to either manually perform memory management to delete the inner vectors when they're no longer needed, use shared pointers rather than raw pointers or use a dedicated pointer container such as boost::ptr_vector.

Thanks for the explanation! I wasn't sure where exactly the pointer would be bound, thank you very much!

I've updated the rest of my code to reflect this, but I'm not sure I'm doing it right. Do you have any good resources you could point me to about multi-dimensional vectors and pointers?

Also, would this be the right way to declare the iterator now?

vector< vector <string>* >::iterator *tableItr;

This is the only way I can get it compile without issue (except for the line with the alphabetical comparison, which I don't know how to fix) and it does not look right at all :psyduck:

code:
for (*tableItr = twoDimStrVec->begin(); !insertComplete && *tableItr != twoDimStrVec->end(); tableItr++)
{
           if (vecRows[0] < &twoDimStrVec[i][0])
           {
                    twoDimStrVec->insert(*tableItr,&vecRows);
                    insertComplete = true;
           } 

           else if (*tableItr == (twoDimStrVec->end() - 1))
           {
                    twoDimStrVec->insert(*tableItr,&vecRows);
                    insertComplete = true;
           }

           else 
                    i++; 
} // end for-loop 
I had the operator [] overloaded to help with the comparison, but that doesn't work now, which I'm assuming is causing the error.

code:
const vector<string> & StringTable::operator[](int i) const
{
    return twoDimStrVec[i];
}
All fixes I've tried to this don't work, either, and hours of Googling have yielded nothing. Vectors and pointers are my two weakest spots and my book covers neither, so to have to return to a vector of strings by address that would work in an alphabetical comparison is pretty rough.

Whilst farting I fucked around with this message at 01:10 on Oct 12, 2008

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

Whilst farting I posted:

Thanks for the explanation! I wasn't sure where exactly the pointer would be bound, thank you very much!

I've updated the rest of my code to reflect this, but I'm not sure I'm doing it right. Do you have any good resources you could point me to about multi-dimensional vectors and pointers?

Also, would this be the right way to declare the iterator now?

vector< vector <string>* >::iterator *tableItr;

This is the only way I can get it compile without issue (except for the line with the alphabetical comparison, which I don't know how to fix) and it does not look right at all :psyduck:

code:
for (*tableItr = twoDimStrVec->begin(); !insertComplete && *tableItr != twoDimStrVec->end(); tableItr++)
{
           if (vecRows[0] < &twoDimStrVec[i][0])
           {
                    twoDimStrVec->insert(*tableItr,&vecRows);
                    insertComplete = true;
           } 

           else if (*tableItr == (twoDimStrVec->end() - 1))
           {
                    twoDimStrVec->insert(*tableItr,&vecRows);
                    insertComplete = true;
           }

           else 
                    i++; 
} // end for-loop 

Just making changes until you get the code to compile doesn't really help you much. I can almost guarantee this code will crash immediately. I'll try to go through this error by error:


code:
// Assuming type: vector< vector <string>* >* twoDimStrVec
// Assuming type: vector<string> vecRows

[b]// This declares tableItr as a pointer-to-an-iterator but allocates
// no memory for the actual iterator[/b]
vector< vector <string>* >::iterator *tableItr;

for (*tableItr = twoDimStrVec->begin(); 
!insertComplete && *tableItr != twoDimStrVec->end(); 
tableItr++) [b]// here you are incrementing the POINTER not the iterator it points to[/b]
{
           [b]// twoDimStrVec is type pointer-to-vector<pointer-to-vector<string>>[/b]
           [b]// twoDimStrVec[i] is the ith offset from the pointer above. You're not[/b]
           [b]//   dereferencing the pointer, so it takes the offset of the pointer[/b]
           [b]//   as if it were a pointer to the first element of an array. The result is a[/b]
           [b]//   vector<pointer-to-vector<string > >, as if it were the ith elemenent in[/b]
           [b]//   an array of vectors of pointers to vectors of strings. But twoDimStrVec is[/b]
           [b]//   not an array, so it's dereferencing some random memory location[/b]
           [b]// twoDimStrVec[i][0] is the 0th element of the vector which supposedly exists at[/b]
           [b]//   that random memory location, a pointer to a vector of strings.[/b]
           [b]// &twoDimStrVec[i][0] is the address of that vector that doesn't exist [/b]
           [b]// I'm assuming vecRows is type vector<string> so here you're comparing a string to[/b]
           [b]//   the address of a pointer to a vector of strings[/b]
           if (vecRows[0] < &twoDimStrVec[i][0])
           {
                    [b]// Here you modify the container you are iterating through, which[/b]
                    [b]//   invalidates your iterators. I know you are going to exit the loop[/b]
                    [b]//   right away because you set insertComplete to true, but the increment[/b]
                    [b]//   statement still executes with undefined behavior. Why not use a[/b]
                    [b]//   break statement instead?[/b]
                    twoDimStrVec->insert(*tableItr,&vecRows);
                    insertComplete = true;
           } 

           else if (*tableItr == (twoDimStrVec->end() - 1))
           {
                    [b]// Same as above[/b]
                    twoDimStrVec->insert(*tableItr,&vecRows);
                    insertComplete = true;
           }

           else 
                    i++; [b]// Why are you using i to index things when you have an iterator?[/b]
} // end for-loop 
Try something like this:

code:
// Assuming type: vector< vector <string>* >* twoDimStrVec
// Assuming type: vector<string> vecRows

vector< vector <string>* >::iterator tableItr; // Just an iterator, not a pointer

for (tableItr = twoDimStrVec->begin(); tableItr != twoDimStrVec->end(); tableItr++)
{
           // tableItr is an interator-into-vector<pointer-to-vector<string> >
           // *tableItr is the current pointer-to-vector<string> that you are iterating on
           // **tableItr is the current vector<string> being pointed to
           // (**tableItr)[0] is the first string in that vector
           if (vecRows[0] < (**tableItr)[0]) 
           {
                    twoDimStrVec->insert(tableItr,&vecRows);
                    break;
           } 

           else if (tableItr == (twoDimStrVec->end() - 1))
           {
                    twoDimStrVec->insert(tableItr,&vecRows);
                    break;
           }
} // end for-loop 
Edit: Oh duh, this is much simpler hurrr. Fixed.

Now I don't see why twoDimStrVec has to be a pointer, but if you make it not be a pointer (i.e. just a plain vector<vector<string>*> instead of a vector<vector<string>*>*), all you need to do is change the parts that say "twoDimStrVec->" to say "twoDimStrVec.", and everything else can stay the same, like this:


code:
// Assuming type: vector< vector <string>* > twoDimStrVec
// Assuming type: vector<string> vecRows

vector< vector <string>* >::iterator tableItr; // Just an iterator, not a pointer

for (tableItr = twoDimStrVec.begin(); tableItr != twoDimStrVec.end(); tableItr++)
{
           // tableItr is an interator-into-vector<pointer-to-vector<string> >
           // *tableItr is the current pointer-to-vector<string> that you are iterating on
           // **tableItr is the current vector<string> being pointed to
           // (**tableItr)[0] is the first string in that vector
           if (vecRows[0] < (**tableItr)[0]) 
           {
                    twoDimStrVec.insert(tableItr,&vecRows);
                    break;
           } 

           else if (tableItr == (twoDimStrVec->end() - 1))
           {
                    twoDimStrVec.insert(tableItr,&vecRows);
                    break;
           }
} // end for-loop 

Smackbilly fucked around with this message at 02:38 on Oct 12, 2008

Adbot
ADBOT LOVES YOU

Whilst farting I
Apr 25, 2006

That's exactly the kind of verbose explanations I need, thank you very much. :) I was totally clueless on pointers and iterators of multi-dimensional vectors - the iterator in particular I knew couldn't be right, especially with the discrepancies between incrementing it and how else it was used in the for-loop. I just feel plain silly for using the integer i, but I didn't know how to use the iterator in that position. Break was just me being an idiot. :doh:

I tried earlier the (*twoDimStrVec[i])[0] method after finding the following link through Google, which I thought helped me to understand everything but then it didn't compile so I was lost again

http://bytes.com/forum/thread677687.html

I should have realized that I was just declaring it wrong, though. I realized it was wrong, but I didn't understand why. I didn't even realize I was declaring it to be a pointer - I thought it was just a vector of pointers to a vector of strings, but I declared a pointer to a vector of pointers to a vector of strings. Your post cleared that up, but looking back at all the things I had wrong, god drat.

Thanks again so much for parsing through that mess of a code and explaining exactly what was wrong with it and what the other things I had been trying meant. I learned more from that one post than I did from several hours of googling, and I definitely understand how all these things are connected now.

Whilst farting I fucked around with this message at 03:04 on Oct 12, 2008

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