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
The Red Baron
Jan 10, 2005

Smackbilly has given a pretty thorough explanation, so I'll just try to give some supplementary info (although it's pretty late, so I may inadvertantly type up something that's not correct)

quote:

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][/i]i];
}
Assuming that twoDimStrVec is of type vector<vector<string>*> (that is, it's not a pointer itself, but it is a vector of pointers), doing twoDimStrVec[index] returns whatever's at index in twoDimStrVec, which in this case is a pointer to a vector<string> instance. To return a reference to this instance, you just have to dereference the pointer, i.e.
code:
const vector<string>& StringTable::operator[](int i) const
{
  return *twoDimStrVec[[i][/i]i];
}
Since the dereference-operator can be overloaded, iterators use it to get a reference to the element they're pointing at, giving them the extremely nice property that from a programmer's point of view, dealing with iterators and plain old pointers for sequence iteration in templated code is identical. As has already been described, if you have multiple dereferences, each dereference goes one step "deeper", working on what resulted from the previous one. If we have a vector<vector<string>*> instance and we have some iterator i pointing into it, doing *i gets us a reference to the element it points to (a pointer to vector<string>). Continuing with **i works on that element, and as we saw earlier in the operator[] example, doing *some_pointer gives us a reference.

If I have understood your problem description correctly, it also seems to me that your code could be greatly simplified. Since you want to step through the vector of existing rows and insert the current row before any element that is lexicographically greater than it is (i.e you have an existing vector [A, C, F] and you're inserting D, you reach a point where you see that D < F), you can break off your loop at that point and insert the row. Conveniently, vector::insert inserts the given element before the element the iterator points to, which is exactly what we want :)

assuming:
rows is an instance of vector<vector<string>*>, and
row is an instance of vector<string>* allocated on the heap per iteration:
code:
while ([i]there is still input[/i])
{
  [i]create and fill row with elements[/i]

  vector<vector<string>*>::iterator i;
  for (i = rows.begin(); i != rows.end(); ++i)
    if ((*row)[0] < (**i)[0])
      break;

  rows.insert(i, row);
}
For each existing row, the first element of the current row is compared to the first element of the vector pointed to by i. If the current row is less, break out and insert. If the current row is greater than all the existing elements, the loop will finish completely and i will be equal to rows.end(). Again, vector::insert inserts before the iterator, so doing rows.insert(i, row) then will insert before the end, which is functionally equivalent to doing rows.push_back(row).

edit: to clarify, the code assumes that a new instance of row is created for each loop iteration, since the rows-vector naturally must be filled with distinct objects to work

The Red Baron fucked around with this message at 05:35 on Oct 12, 2008

Adbot
ADBOT LOVES YOU

Whilst farting I
Apr 25, 2006

Thanks a ton for going into more specifics! It's frustrating how difficult it is to find this kind of information in a clear, concise manner online, using non-complicated examples. I'm still a little confused about dereferencing, though - how does it know when to deallocate the memory? Does that have to be done in a destructor?

While that really compact for-loop looks appealing, it won't run if it's empty - there's nothing in the table yet. The beginning is the end. I added a check to see if it was empty and made it into an if-else statement. But there's a problem. I added a lot of other code just to make sure the problem wasn't the method - it happens no matter which method I use, as long as it involves that specific for-loop and comparison.

It seems that no matter what, (**tableItr) is always the first element of the row being inserted. It doesn't start at the beginning of the table. In fact, even though the iterator is told to increment, it doesn't move at all. At the beginning of every for-loop, (**tableItr) is the very first element of the current row. I've added some debug statements.

code:
while (data to be read)
{

vector< vector <string>* >::iterator tableItr = twoDimStrVec.begin();

if (twoDimStrVec.empty())
{
    twoDimStrVec.insert(tableItr,&vecRows);
}

else
{
	for (tableItr = twoDimStrVec.begin(); tableItr != twoDimStrVec.end(); tableItr++)
        {
           cout << "*tableItr is " << (*tableItr) << endl;
	   cout << "**tableItr before the for-loop is " << (**tableItr)[0] << endl;

           if (vecRows[0] <= (**tableItr)[0])
           {
                 cout << "Table size is " << twoDimStrVec.size() << endl;
                 cout << "Row 0 is " << vecRows[0] << endl;
                 cout << "**tableItr is " << (**tableItr)[0] << endl;
			
                 twoDimStrVec.insert(tableItr,&vecRows);
			
                 cout << "Table size is " << twoDimStrVec.size() << endl;
                 break;
            }

            else if (tableItr == (twoDimStrVec.end() - 1))
            {
                cout << "Pushin back" << endl;
			
                twoDimStrVec.insert(tableItr,&vecRows);
                break;
            }
     } // end for-loop
} // end else
}// end while
Here's the output that gives.

(the first element was Alan, but I did not include a cout statement in the "if empty" loop)

*tableItr is 0xffffffff7ffff450
**tableItr before the for-loop is Bob
Table size is 1
Row 0 is Bob
**tableItr is Bob
Table size is 2

*tableItr is 0xffffffff7ffff450
**tableItr before the for-loop is Charles
Table size is 2
Row 0 is Charles
**tableItr is Charles
Table size is 3

*tableItr is 0xffffffff7ffff450
**tableItr before the for-loop is Clementine
Table size is 3
Row 0 is Clementine
**tableItr is Clementine
Table size is 4

:psyduck:

So obviously things aren't getting added in lexographical order because each row is being compared to its own first element instead of the first element of the nth row the table (twoDimStrVec). It never gets beyond that first if statement, because it's always true. Taking away the equal sign resulted in other errors, and does not solve the problem of (**tableItr)[0] always being of the current row.

The second time through should be

if (Bob <= Alan)

Instead, it's

if (Bob <= Bob)

The iterator is not being incremented. I don't know what the hell it's doing.

I found something here

http://www.velocityreviews.com/forums/t456722-segmentation-fault-calling-insert-on-vector.html

That suggests that "insert" returns some kind of iterator each time it's called - but how can that be fixed, and why am I not seeing a ton of other people having problems like this?

I found another case with a similar problem, but it's a few years old and he never got an answer.

http://www.daniweb.com/forums/thread34928.html

awesmoe
Nov 30, 2005

Pillbug
Using pointers, the following is pretty common
code:
class Bob{...}; //abstract base class Bob
class Foo : public Bob {...};
class Bar : public Bob {...};

const Foo* getFoo(){/*return a new foo*/}
const Bar* getBar(){/*return a new bar*/}

void main(){
    const Bob *bob = null;
    if (a==b){
        bob = getFoo();
    } else {
        bob = getBar();
    }
    //use bob
}
However, as I understand things, it just doesn't work using references, as you cant define the initial Bob (since it's abstract)

code:
const Foo& getFoo(){/*return a Foo&*/}
const Bar& getBar(){/*return a Bar&*/}

void main(){
    const Bob &bob; // error: ‘bob’ declared as reference but not initialized
    if (a==b){
        bob = getFoo();
    } else {
        bob = getBar();
    }
    //use bob
}
Is there a way of doing this that I'm missing? I'm specifically looking at the case where the Bob& can't be declared in the scope of the if block

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
code:
bob = getFoo();
This has completely different semantics in your two examples.

EDIT: Sorry if you understood that; late night snark is not helpful. Basically, no, there's no way to do what you want to do, at least not unless you can't rework it to use a ternary operator: the referent of a reference variable has to be fixed at the time of creation.

rjmccall fucked around with this message at 10:18 on Oct 12, 2008

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

quote:

While that really compact for-loop looks appealing, it won't run if it's empty - there's nothing in the table yet. The beginning is the end. I added a check to see if it was empty and made it into an if-else statement. But there's a problem. I added a lot of other code just to make sure the problem wasn't the method - it happens no matter which method I use, as long as it involves that specific for-loop and comparison.

<snip>

Here's the problem: you're re-using the same vecRows object over and over again for each row, and you're storing a pointer to it in the table. When you insert a pointer to the vecRows object into the table, you are not copying the contents of the vecRows vector into the table; you are only pointing back to it. So if you insert a pointer to vecRows into table slot 0, that means that when you later retrieve the contents of table slot 0, it just follows the pointer and reads whatever is currently in the vecRows object that you have a pointer to.

So when you insert a pointer to the vecRows object, and then you then overwrite the vecRows object's contents with the next row, dereferencing the pointer in the table will then get you the new data in vecRows (because remember no copy was ever made). In short: because the table contains a pointer to the row vector, changing the contents of the row vector changes the contents of the table.

This problem is really easy to avoid in the following manner: don't use pointers. There is absolutely no reason for you to be using pointers here. When I saw the code snippet you posted earlier, I assumed that there was some good reason why twoDimStrVec was a vector of pointers-to-vectors rather than a vector of vectors. I looked back through the thread to your initial post, and there's no reason at all for that to be the case.

Just do this and all will be well:
code:
[b]// Assuming type: vector<vector<string> > twoDimStrVec[/b]
[b]// Assuming type: vector<string> rowVec[/b]

while (data to be read)
{

vector< vector <string> >::iterator tableItr = twoDimStrVec.begin();

if (twoDimStrVec.empty())
{
    twoDimStrVec.insert(tableItr, vecRows); // Note the lack of &
}

else
{
	for (tableItr = twoDimStrVec.begin(); tableItr != twoDimStrVec.end(); tableItr++)
        {
           // Note *tableItr instead of **tableItr, because there's no pointer
           // involved, just getting the value of the current iterator position
           if (vecRows[0] <= (*tableItr)[0])
           {
                 twoDimStrVec.insert(tableItr,vecRows); // Note no &
                 break;
            }

            else if (tableItr == (twoDimStrVec.end() - 1))
            {
                twoDimStrVec.insert(tableItr, vecRows); // Note no &
                break;
            }
     } // end for-loop
} // end else
}// end while
Even simpler than what you had before, and it has the semantics you want. When you do twoDimStrVec.insert(tableItr, vecRows), it makes a copy of the contents of vecRows and puts that data directly into twoDimStrVec. Since you now have a copy of the contents in the table, rather than a reference back to the row vector, you can now overwrite the contents of the row vector without changing the contents of the table.

Almost all of your confusion here seems to be because you are really eager to use lots of pointers when they are not necessary. No part of this process that we are helping you debug requires the use of any pointers. I suggest that you do some further reading on pointers (even the Wikipedia article or something) to help yourself understand what pointers really do and when/why they are necessary.

Whilst farting I
Apr 25, 2006

It needs to be a vector of pointers to vectors of strings, though - this file is massive. This hit the nail on the head as to why I need to do it:

The Red Baron posted:

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.

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

Whilst farting I posted:

It needs to be a vector of pointers to vectors of strings, though - this file is massive. This hit the nail on the head as to why I need to do it:

Well, first of all I'm not convinced that using pointers will really make your program go all that much faster. This program is executing a loop of the form 1. read some data from disk, 2. move some stuff around in memory. Disk I/O is exponentially slower than memory access, so 90%+ of your program's time is going to be spent on step (1) rather than step (2) and making step (2) faster won't help all that much.

But if you insist on using pointers, what you have to do is make vecRows into a pointer, and allocate new memory for it each time you start reading a new row. Declare vecRows as type vector<string>*, and replace the vecRows.clear() line with vecRows = new vector<string>().

Then, update the rest of the method so that vecRows[0] becomes (*vecRows)[0] (dereference the pointer to get the vector it points to before using the [] operator) and &vecRows becomes vecRows (no longer need to take the address, since vecRows is now itself a pointer).

Now since you are allocating a new vector every time you read a row, you are no longer overwriting the contents of the vector that you have already stored a pointer to in the table.

The downside of this is that you now have to worry about manually releasing that memory when it is no longer used, or else you will have a memory leak in your program. At minimum, this means defining a destructor for your class and having it iterate through twoDimStrVec, and call "delete *tblItr" (assuming that's what you call the iterator again. If your class provides a method to remove rows from the table, then you will have to call delete on the row pointers when you remove them from the table as well.

awesmoe
Nov 30, 2005

Pillbug

rjmccall posted:

code:
bob = getFoo();
This has completely different semantics in your two examples.

EDIT: Sorry if you understood that; late night snark is not helpful. Basically, no, there's no way to do what you want to do, at least not unless you can't rework it to use a ternary operator: the referent of a reference variable has to be fixed at the time of creation.


Less than helpful, I'm afraid, because now I'm confused as to whether my example was unclear or whether the thing I'm actually trying to do is just crazy! I really appreciate the help though :)

I'm thinking about the case where getFoo() and getBar() are member functions of something, returning const pointers (or const references) to existing objects. With a base class pointer, you get the derived class behaviour, with a base class reference you get a compile error.

It seems like a hole in the language, to me - if you're going to make references use polymorphism, then they should be able to use the abstract base class functionality as well, as I see it?
If it is a hole in the language that's understandable - I'm not insisting that the language is perfect - I'm just wondering if there's a design rationale behind this that I'm missing.
As I said, thanks heaps for the comments - they're most helpful.

Avenging Dentist
Oct 1, 2005

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

awesmoe posted:

It seems like a hole in the language, to me - if you're going to make references use polymorphism, then they should be able to use the abstract base class functionality as well, as I see it?

No it isn't. You just can't change what a reference points to after you declare it. Think of it like a Foo * const.

Besides, you can still do
code:
const Bob& getFoo(){ ... }
const Bob& getBar(){ ... }

...

const Bob &bob = (a==b) ? getFoo():getBar();

Gary2863
Jul 19, 2000

I'm just starting to learn C++, my first computer language, and I've decided to test what I've learned by making a simple program that converts between Fahrenheit and Celsius. I'm using a switch case statement, and a user types 1 or 2 to choose either Fahrenheit or Celsius. Everything works fine there. But if they accidentally choose some other number, the program just shuts down. Isn't cin.get() supposed to prevent this, forcing the program, with the error message I included, to stay visible until the user hits enter?

Here's my program:

code:
#include <iostream>
using namespace std;

int main()
{
  int scale;
  
  cout<<"Type 1 or 2, then press Enter, to choose your starting temperature scale.\n"; 
  cout<<"1. Fahrenheit\n";
  cout<<"2. Celcius\n";
  cin>> scale;
  switch ( scale ) {
  case 1:            
    int Fahr;
    cout<< "Please type a Fahrenheit temperature. \n";
    cin>> Fahr;
    cin.ignore();
    cout<< "Your Celsius temperature is: \n";
    cout<< 5*(Fahr-32)/9 ;
    cout<< "\n Press Enter to quit. \n";
    break;
  case 2:          
    int Cels;
    cout<< "Please type a Celsius temperature. \n";
    cin>> Cels;
    cin.ignore();
    cout<< "Your Celsius temperature is: \n";
    cout<< 32 + 9*Cels/5 ;
    cout<< "\n Press Enter to quit. \n";
    break;
  default:        
    cout<<"Error: You chose something other than 1 or 2. Press Enter to quit. \n";
    break;
    cin.get();
  }
  cin.get();
}

Whilst farting I
Apr 25, 2006

Smackbilly posted:

Well, first of all I'm not convinced that using pointers will really make your program go all that much faster. This program is executing a loop of the form 1. read some data from disk, 2. move some stuff around in memory. Disk I/O is exponentially slower than memory access, so 90%+ of your program's time is going to be spent on step (1) rather than step (2) and making step (2) faster won't help all that much.

Obviously it won't run lightning quick, but isn't it faster to run it and output elements by passing the address of the element to be printed rather than passing the entire element itself?

quote:

But if you insist on using pointers, what you have to do is make vecRows into a pointer, and allocate new memory for it each time you start reading a new row. Declare vecRows as type vector<string>*, and replace the vecRows.clear() line with vecRows = new vector<string>().

Then, update the rest of the method so that vecRows[0] becomes (*vecRows)[0] (dereference the pointer to get the vector it points to before using the [] operator) and &vecRows becomes vecRows (no longer need to take the address, since vecRows is now itself a pointer).

Now since you are allocating a new vector every time you read a row, you are no longer overwriting the contents of the vector that you have already stored a pointer to in the table.

I knew it had something to do with declaring a new vector every time through the loop - I tried setting vecRows = new vector<string> but the compiler didn't like that. I knew I had to make vecRows into a pointer, too - but again, the syntax (and a bit of the logic) escaped me. :gbsmith:

quote:

The downside of this is that you now have to worry about manually releasing that memory when it is no longer used, or else you will have a memory leak in your program. At minimum, this means defining a destructor for your class and having it iterate through twoDimStrVec, and call "delete *tblItr" (assuming that's what you call the iterator again. If your class provides a method to remove rows from the table, then you will have to call delete on the row pointers when you remove them from the table as well.

"delete *tblItr" releases the memory location at *tableItr but the memory location will still have the elements in them, if I'm understanding this correctly?

Like if 0x10010b2b0 holds "Alan", if I don't release that memory by the time the program is finished executing, no other program will be able to use that memory and it will still hold "Alan." However, if I do release the memory, other programs will be able to use 0x10010b2b0, but it will still hold "Alan" but other programs will just overwrite it.

If this is the case, how bad is it to not delete the row pointers and where exactly do they fit in?

The Red Baron
Jan 10, 2005

Whilst farting I posted:

Obviously it won't run lightning quick, but isn't it faster to run it and output elements by passing the address of the element to be printed rather than passing the entire element itself?
If by outputting you mean using "std::cout << whatever", it uses references anyway, which means it'll never be copying the entire element just to print it.

quote:

"delete *tblItr" releases the memory location at *tableItr but the memory location will still have the elements in them, if I'm understanding this correctly?
Attempting to access a memory location after it has been deleted is undefined behaviour country. The elements may potentially still be there, but that's simply because they haven't been overwritten by new allocations yet.

quote:

Like if 0x10010b2b0 holds "Alan", if I don't release that memory by the time the program is finished executing, no other program will be able to use that memory and it will still hold "Alan." However, if I do release the memory, other programs will be able to use 0x10010b2b0, but it will still hold "Alan" but other programs will just overwrite it.

If this is the case, how bad is it to not delete the row pointers and where exactly do they fit in?
A process' address space belongs to it and it alone, and no other process can mess with it (not counting stuff like shared memory etc. here, that's beside the point). Whenever a process exits, cleanly or not, the operating system will release all the physical memory that process used. You do not risk having any other process overwriting memory that is still in your process' address space, nor will memory you have not freed stay permanently unavailable to other processes. However, if you do not properly free memory during the course of your process, you will of course end up with a memory leak that may cause low memory problems when run for a long time etc.

I doubt this will be a showstopper-problem with your current application unless the datasets you process are truly immense or you're running it over and over again for a long time without exiting it, but getting a good practice down as soon as possible when it comes to memory management is a Good Thing(tm). The thing with C++ is that despite what many people believe, getting memory management right is pretty straight forward. Learn how std::auto_ptr and boost::shared_ptr work, what their application areas and limitations are (the latter in particular for auto_ptr), understand how scopes work, and read up on RAII (Resource Acquisition is Initialization). These are pretty much crucial to writing code that won't poo poo itself when exceptions start entering the picture, and will also make writing code much more enjoyable :)

magicalblender
Sep 29, 2007

Gary2863 posted:

Isn't cin.get() supposed to prevent this, forcing the program, with the error message I included, to stay visible until the user hits enter?
[snip]
default:
cout<<"Error: You chose something other than 1 or 2. Press Enter to quit. \n";
break;
cin.get();



I guess you ought to put cin.get() before break. Otherwise that line is unreachable and never gets executed.

slovach
Oct 6, 2005
Lennie Fuckin' Briscoe

Gary2863 posted:

words

Shouldn't you clear the input buffer before you try to use cin.get / ignore?

Also, you're not returning anything.

LLJKSiLk
Jul 7, 2005

by Athanatos
Web Service returning DataSet to Web Page

Okay, I have a WebService I've written providing return DataSet's to another programmer who is designing an aspx webpage using the GridView to display the returned data.

On Page Load he is doing a Bind() to the returned DataSet and displaying the results in his Grid.

This works fine. What he is wanting to do at this point, is click a link over any of the columns in the Gridview and sort/resort the Data which he bound to the grid.

I figured the DataSet still exists in memory or somewhere and he shouldn't have a problem manipulating from another event on the Grid. But he says this won't work.

Any reason why returned datasets can't be manipulated after they've been loaded into a page? If there is a way to do this - is the fix on my end or his?

Anyone have any ideas?

tef
May 30, 2004

-> some l-system crap ->
I think you might want the .NET thread, http://forums.somethingawful.com/showthread.php?threadid=2262300

Gary2863
Jul 19, 2000

magicalblender posted:

I guess you ought to put cin.get() before break. Otherwise that line is unreachable and never gets executed.

You got it, this fixed it. Thanks!

slovach posted:

Shouldn't you clear the input buffer before you try to use cin.get / ignore?

Also, you're not returning anything.

I'm very new at this, I made the temperature converter on my first day of working with C++. I read somewhere that programs return a 0 to the operating system if they run successfully, but I wasn't sure what the importance of that was. Is that what you're talking about?

Also, I don't know how to clear the input buffer yet. The program seems to do its job perfectly now even if it's not the way it should be coded. Still, I appreciate any clear advice about it, just please be aware I am at the very beginning of the learning process here.

The Lost
Dec 7, 2005
Boredom is my only excuse.

Gary2863 posted:

I'm just starting to learn C++, my first computer language, and I've decided to test what I've learned by making a simple program that converts between Fahrenheit and Celsius. I'm using a switch case statement, and a user types 1 or 2 to choose either Fahrenheit or Celsius. Everything works fine there. But if they accidentally choose some other number, the program just shuts down. Isn't cin.get() supposed to prevent this, forcing the program, with the error message I included, to stay visible until the user hits enter?
[chop]

You can also use your OS to pause, clear the screen and other fun stuff.
code:
#include <stdlib.h>
#include <iostream> 

using namespace std; 

int main() {
   int integer;
   cout<<"1> Option 1\n"
       <<"2> option 2\n\n"
       <<"Enter your selection:";
   cin>>integer;

   switch(integer){
      case 1:
         cout<<"Do your stuff here.\n";
         break;
      case 2:
         cout<<"Do something different here.\n";
         break;
      default:
         //You don't need to break on default.
         cout<<"You fail at life.  Try reading the directions.\n";
   }
   system("pause"); //The C-Style string is the operating system specific command.
                    // So this only works on windows, for unix it will depend on 
                    // your shell & flavor of unix.
   return 0;
}
the system command can issue any OS command line call you want to make. Great for pausing and clearing screen.
code:
     system("cls"); //windows
Lastly, always ignore before using a cin.get() to prompt the user. Ignore assures there are no characters in the buffer. If you don't there will be spaces and newlines left over in the buffer.
code:
For example in the program above, if the user typed in 2 the buffer would initially have:
     2\n
Thats the 2 plus the new line for the enter key.
After the cin the buffer will have:
     \n
that means that if I used a cin.get() in place of the system("pause") it would read the \n and continue on, thus not pausing the screen as you hoped for.  If you use an ignore like:
     cin.ignore(10,'\n');
it will read the next 10 characters or until it finds the new line.  So the breakdown would be:
     2\n  [cin>>integer;]---> Reads out the 2
     \n   [cin.ignore(10,'\n');]---> Reads/ignores out the \n
          [cin.get();]---> shows the prompt because buffer is empty.
Hope that helps.
[/book]

Avenging Dentist
Oct 1, 2005

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

The Lost posted:

the system command can issue any OS command line call you want to make. Great for pausing and clearing screen.
code:
     system("cls"); //windows

Generally speaking, this is inadvisable. Besides being non-portable (obviously), it places a lot of assumptions on how your application is being used. It's better to avoid system calls wherever possible; rather than using a system call to pause, it's better to just open a command prompt and run from there. Or, if you really need all kinds of whiz-bang stuff to mess with the console, use something like ncurses.

electric_vaseline
Mar 30, 2007
Feel the electricity...in your pants.
So, hopefully really simple question:

I'm used to Java, and I'm trying to pass a single character into a vector<string>, which apparently isn't just automatically cast up. Do I actually have to do something ridiculous like:
code:
string temp = "";
temp.append(c_string_i'm_adding_parts_of_to_this_vector[i]);
vector.push_back(temp);
Or is there some way I can make it just cast the character?

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
temp += c_string[i]

Edit: Or that VVV (that's what I get for skimming)

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

TOO SCSI FOR MY CAT
Oct 12, 2008

this is what happens when you take UI design away from engineers and give it to a bunch of hipster art student "designers"

electric_vaseline posted:

So, hopefully really simple question:

I'm used to Java, and I'm trying to pass a single character into a vector<string>, which apparently isn't just automatically cast up. Or is there some way I can make it just cast the character?

char c = 'a';
std::vector<std::string> myvector;
myvector.push_back (std::string (1, c));

TOO SCSI FOR MY CAT fucked around with this message at 00:01 on Oct 14, 2008

Whilst farting I
Apr 25, 2006

The Red Baron posted:

If by outputting you mean using "std::cout << whatever", it uses references anyway, which means it'll never be copying the entire element just to print it.

Attempting to access a memory location after it has been deleted is undefined behaviour country. The elements may potentially still be there, but that's simply because they haven't been overwritten by new allocations yet.

A process' address space belongs to it and it alone, and no other process can mess with it (not counting stuff like shared memory etc. here, that's beside the point). Whenever a process exits, cleanly or not, the operating system will release all the physical memory that process used. You do not risk having any other process overwriting memory that is still in your process' address space, nor will memory you have not freed stay permanently unavailable to other processes. However, if you do not properly free memory during the course of your process, you will of course end up with a memory leak that may cause low memory problems when run for a long time etc.

I doubt this will be a showstopper-problem with your current application unless the datasets you process are truly immense or you're running it over and over again for a long time without exiting it, but getting a good practice down as soon as possible when it comes to memory management is a Good Thing(tm). The thing with C++ is that despite what many people believe, getting memory management right is pretty straight forward. Learn how std::auto_ptr and boost::shared_ptr work, what their application areas and limitations are (the latter in particular for auto_ptr), understand how scopes work, and read up on RAII (Resource Acquisition is Initialization). These are pretty much crucial to writing code that won't poo poo itself when exceptions start entering the picture, and will also make writing code much more enjoyable :)

The dataset is indeed truly immense - it's several thousand lines long. I've never heard of RAII or the other things you mentioned, I'm looking into that now. Basically I had a very vague idea about all this and you snapped it all into place.

This has been truly enlightening, especially about pointers and memory leaks and deallocation - thank you to all who helped me. I'd offer gift certs for being so clear and helping me to gain an understanding of what the hell I'm doing, but I'm flat-broke. :nyoron: I learned way more from your posts than I did from several different C++ books I consulted and anything I could find online. Thanks again for the detail and clarity!

Whilst farting I fucked around with this message at 00:48 on Oct 14, 2008

electric_vaseline
Mar 30, 2007
Feel the electricity...in your pants.

Janin posted:

char c = 'a';
std::vector<std::string> myvector;
myvector.push_back (std::string (1, c));
Thanks! That did it.

Avenging Dentist posted:

temp += c_string[i]

Edit: Or that VVV (that's what I get for skimming)
That would fix the example I gave as the append wouldn't have actually worked but it's the same effect.

It did help though with another problem I was having with using append as I didn't think += would work in C++, so thanks!

(Btw, VVV?)

TOO SCSI FOR MY CAT
Oct 12, 2008

this is what happens when you take UI design away from engineers and give it to a bunch of hipster art student "designers"

electric_vaseline posted:

(Btw, VVV?)

^^^ and VVV are used to indicate other posts.

electric_vaseline
Mar 30, 2007
Feel the electricity...in your pants.

Janin posted:

^^^ and VVV are used to indicate other posts.


Ah! Of course.

Well, new question. I keep getting this error message and I've been pounding my head for hours trying to figure it out but I can't.

The error:

quote:

1>Tester.obj : error LNK2019: unresolved external symbol "public: static class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl Utility::Join(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)" (?Join@Utility@@SA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$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@@3@D@Z) referenced in function _main

The offending code:
code:
#include "Utility.h"
#include <stdio.h>

int main(void)
{
	Utility::WelcomeMessage("Hello", "Welcome");
	vector<string> strings  = Utility::Split("Hello my name is 1 + fgdfgdf.", " +.");
	string joined = "";
	joined = Utility::Join(strings, ' ');
	cout << joined;
	getchar();
	return 0;
}
The method join (the error only comes up when the join method is called):
code:
string Join (const vector<string> vInput, const char cSeparator)
{
	string joinedString = "";
	int columnCount = 0;
	for each(string s in vInput)
	{
		int length = s.length();
		if(columnCount + length >= 80)
		{
			joinedString += "\n";
			columnCount = 0;
		}
		joinedString += s + cSeparator;
		columnCount += length + 1;
	}
	return joinedString;
}

csammis
Aug 26, 2003

Mental Institution
The linker is saying it can't find Utility::Void. If the Void method is defined in the class Utility, you need to declare that as part of the method signature:

code:
string Utility::Join (const vector<string> vInput, const char cSeparator)
{ 
}

electric_vaseline
Mar 30, 2007
Feel the electricity...in your pants.

csammis posted:

The linker is saying it can't find Utility::Void. If the Void method is defined in the class Utility, you need to declare that as part of the method signature:

Oh! Crap! Of course!

Hahaha, I can't believe I forgot the Utility::

The Red Baron
Jan 10, 2005

Also, please change const vector<string> vInput to const vector<string>& vInput :shobon: You really don't want to be passing vectors around by value

The Lost
Dec 7, 2005
Boredom is my only excuse.

Avenging Dentist posted:

Generally speaking, this is inadvisable. Besides being non-portable (obviously), it places a lot of assumptions on how your application is being used. It's better to avoid system calls wherever possible; rather than using a system call to pause, it's better to just open a command prompt and run from there. Or, if you really need all kinds of whiz-bang stuff to mess with the console, use something like ncurses.

ncurses is problematic because its a non-standard library, so a beginner would then have to either install extra libaries and/or know how to set up your linker to use non-system libraries. So unless your constrained to a system w/o any graphics libraries/capabilities you might as well start looking a some form of graphical programming. Or start using Java if your field permits.

System is non-portable, but is standard C/C++. If your seriously worried about portability then you can set up pre-compiler directives to set a proper value to a c-string #define and use that in place of the string literal "cls" or whatever.

System is a nice easy cheese console function that doesn't require any serious back ground. Its great for playing around with console apps when your just starting out. Use it or don't. Its just a thought.

floWenoL
Oct 23, 2002

Whilst farting I posted:

The dataset is indeed truly immense - it's several thousand lines long.

Since when was several thousand lines an "immense" dataset? :confused:

Avenging Dentist
Oct 1, 2005

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

The Lost posted:

:words:

No, my main point was that using system calls puts a lot of assumptions on your console app and 99% of them are unnecessary. system("pause") is my least favorite since people always use it as a workaround for the fact that Windows closes command prompts on termination when you double-click on the exe. Just open a command prompt first, or just use Visual Studio which will leave the command prompt open anyway. And if you're not using Visual Studio on Windows, you're honestly kinda dumb.

csammis
Aug 26, 2003

Mental Institution

Avenging Dentist posted:

just use Visual Studio which will leave the command prompt open anyway.

only if you run the program without debugging. If you start it using the debugger, it'll close on exit. It's unfortunate but true :smith:

Avenging Dentist
Oct 1, 2005

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

cronio
Feb 15, 2002
Drifter
How about just cin.get(), getc()... ?

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
I think pretty much anything trying to force a pause in a console app is kinda dumb. If you're just learning how to program, you shouldn't really be worried about usability, just about learning the concepts. If you're an experienced programmer writing a console app, you should be using command line arguments anyway. I mean, at the end of the day, do whatever you want, but I think stuff like that is kinda hacky, and really a lot less useful than people make it out to be.

Gary the Llama
Mar 16, 2007
SHIGERU MIYAMOTO IS MY ILLEGITIMATE FATHER!!!
I'm a C# web application programmer by day, but I've been brushing up on my C/C++ skills by going back through K&R and Accelerated C++. I've been working on a few games off and on but not a whole lot of other projects in C/C++. What are some other good projects to work on that would be an advantage for the language? I've thought about learning some embedded programming but barely know where to start. Any recommendations? (Guess I'm just looking to write programs that are closer to the metal. Of course, nothing too complicated right now. I'm not going to be writing an OS kernel yet.)

The Lost
Dec 7, 2005
Boredom is my only excuse.

Avenging Dentist posted:

I think pretty much anything trying to force a pause in a console app is kinda dumb. If you're just learning how to program, you shouldn't really be worried about usability, just about learning the concepts. If you're an experienced programmer writing a console app, you should be using command line arguments anyway. I mean, at the end of the day, do whatever you want, but I think stuff like that is kinda hacky, and really a lot less useful than people make it out to be.

The program you’re going to write will read 10 names from a file. Then print a menu. The user can select to search for a name, print all the names or exit. If the user chooses to search for a name clear the screen, prompt for the name, then search the list of 10 names. If the name is found print the number of the record in the list of names. If not print an error message. In either case pause for user input before clearing the screen and returning to the menu. If the user chooses to print all the names, print the record number then the name. Pause for user input and then clear the screen and return to the menu. If the user chooses to exit, clear the screen and print a termination message.

This is the type of program I typically run for a second semester programming class to review arrays and introduce searching/sorting. Sure I could make it less interactive. Hell you could read all the user input from a file. However capturing student interest and providing them with the opportunity to do something that feels closer to the types of programs they want to write is an essential tool in teaching. It helps to get the students to think in the direction we want while allowing them to do something that interests them. The hope of course is that as they work on the guts of the assignment they become more interested in the mechanics than the show.

Of course if you’re not worried about teaching people how to program and are focused on actual console projects then yeah, no real point in pausing, clearing the screen or anything else.

cronio
Feb 15, 2002
Drifter

Avenging Dentist posted:

I think pretty much anything trying to force a pause in a console app is kinda dumb. If you're just learning how to program, you shouldn't really be worried about usability, just about learning the concepts. If you're an experienced programmer writing a console app, you should be using command line arguments anyway. I mean, at the end of the day, do whatever you want, but I think stuff like that is kinda hacky, and really a lot less useful than people make it out to be.

Hard to learn the concepts if you can't see what your program is outputting though. While there are other ways around this, grabbing a character from input is fine if you want to just hit F5 in VS. Worrying about details like breakpoints when you're writing your first application is just silly.

I wasn't really paying attention to the thread, I see he already was using cin.get(). I agree that system("pause") is a horrible thing to do.

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

cronio posted:

Hard to learn the concepts if you can't see what your program is outputting though. While there are other ways around this, grabbing a character from input is fine if you want to just hit F5 in VS. Worrying about details like breakpoints when you're writing your first application is just silly.

I don't see why you'd run in debug mode unless you have breakpoints set. Running without debug (Ctrl+F5) will keep the command prompt open, and if you compiled in debug mode, the JIT debugger will load up if something goes haywire anyway.

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