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
Sabotaged
Jul 6, 2004

Okay, I've been using a lot of STL lately, and it scares me a lot because I don't really understand how something like an stl string manages its memory.

If I declare a regular std::string foo, it would automatically allocate itself on the heap I'm assuming? Does it use reference counting or something to determine when to automatically delete itself?

What about string's c_str? Where is this memory? I assume there are no guarantees using this memory outside the immediate scope of the string?

Adbot
ADBOT LOVES YOU

Entheogen
Aug 30, 2004

by Fragmaster

Sabotaged posted:

Okay, I've been using a lot of STL lately, and it scares me a lot because I don't really understand how something like an stl string manages its memory.

If I declare a regular std::string foo, it would automatically allocate itself on the heap I'm assuming? Does it use reference counting or something to determine when to automatically delete itself?

What about string's c_str? Where is this memory? I assume there are no guarantees using this memory outside the immediate scope of the string?

I am probably wrong, but I think string allocates itself on stack if you allocate it on stack and just wraps char * inside of it. It deletes itself when it is popped from stack or when you delete it yourself assuming you put it into dynamic memory.

sarehu
Apr 20, 2007

(call/cc call/cc)

Entheogen posted:

I am probably wrong, but I think string allocates itself on stack if you allocate it on stack and just wraps char * inside of it. It deletes itself when it is popped from stack or when you delete it yourself assuming you put it into dynamic memory.

Lololololololololololololonononononononononononono!

Just imagine that a string is the same thing (internally) as a std::vector<char> -- that's a close enough approximation.

sarehu fucked around with this message at 04:28 on Jul 22, 2008

Vanadium
Jan 8, 2005

Sabotaged posted:

If I declare a regular std::string foo, it would automatically allocate itself on the heap I'm assuming? Does it use reference counting or something to determine when to automatically delete itself?

What about string's c_str? Where is this memory? I assume there are no guarantees using this memory outside the immediate scope of the string?

The string object is on the stack. Then it goes and allocates a bunch of memory on the heap for the string data. This memory will be deallocated when the string object itself goes out of scope. This is achieved by the string object's destructor.

The c_str() memory is on the heap, too. There are indeed no guarantees about using that memory outside the immediate scope of the string. You are not even guaranteed that it is usable if you edit the string after calling c_str(), I think.

Sabotaged
Jul 6, 2004

That makes sense, but what about vectors? Is it the same deal? I could swear I remember seeing some code where a vector was declared within a method, but then returned as the result.

Avenging Dentist
Oct 1, 2005

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

Sabotaged posted:

That makes sense, but what about vectors? Is it the same deal? I could swear I remember seeing some code where a vector was declared within a method, but then returned as the result.

That makes a copy of the vector using its copy constructor.*


* Does not apply to C++0x

Sabotaged
Jul 6, 2004

Avenging Dentist posted:

That makes a copy of the vector using its copy constructor.*


* Does not apply to C++0x

Ah, I see. Does this apply to other stl containers? What about string?

Avenging Dentist
Oct 1, 2005

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

code:
my_dumb_object some_function()
{
    my_dumb_object x;
    // Do some stuff
    return x;
}

my_dumb_object some_other_function()
{
    return my_dumb_object();
}

// ...

some_function(); // Copy ctor is invoked here
some_other_function(); // Copy ctor is NOT invoked here due to "return value optimization"

TSDK
Nov 24, 2003

I got a wooden uploading this one

Avenging Dentist posted:

Yes.
Some compilers will do Named Return Value Optimisation as well as just Return Value Optimisation:
http://msdn.microsoft.com/en-us/library/ms364057(VS.80).aspx

Big Mark
Feb 4, 2003
eighties computer game avatar
What, precisely, is the difference between a reference to a variable and a pointer to it? I've always thought of a reference as being a pointer with nicer syntax but apparently this is very very wrong.

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.

Big Mark posted:

What, precisely, is the difference between a reference to a variable and a pointer to it? I've always thought of a reference as being a pointer with nicer syntax but apparently this is very very wrong.

It's a pointer with nicer syntax that is guaranteed never to be NULL. That second bit is important, because it means you can never declare a reference variable and just leave it with nothing meaningful in it until you do some more calculation. (That means no "Object &some_object; if (cond) { ... initialize one way ... } else { ... initialize another way ... }")

And you can't do pointer arithmetic on it, or do funny casts. Which (I think) means the compiler's better able to optimize it.

TSDK
Nov 24, 2003

I got a wooden uploading this one

Big Mark posted:

What, precisely, is the difference between a reference to a variable and a pointer to it? I've always thought of a reference as being a pointer with nicer syntax but apparently this is very very wrong.
References don't even need to be pointers. For example, if you wrote:
code:
int main()
{
    int a = 10;
    int &b = a;
    b = 20;
    printf( "%d", a );
}
Then the compiler would almost certainly produce identical code to:
code:
int main()
{
    int a = 10;
    a = 20;
    printf( "%d", a );
}
There's also some additional rules about const references to temporaries affecting the lifetime of those temps, but nothing that comes up as a regular occurence.

litghost
May 26, 2004
Builder

JoeNotCharles posted:

It's a pointer with nicer syntax that is guaranteed never to be NULL.

I am sorry to say this completely wrong. C++ lets you do terrible terrible things sometimes:

code:
#include <iostream>

struct Aclass
{
	int b,c,d;
};


int main(int argc, char argv[])
{
	Aclass * bob = (Aclass*)0;
	Aclass & ref_bob = *bob;

	Aclass * bob2 = new Aclass;
	Aclass & ref_bob2 = *bob2;

	ref_bob2.c = 5;

	delete bob2;


	ref_bob2.c = 1234123;  // Oh noes, corrupted heap

	std::cout << "A null pointer : " << bob << std::endl;
	std::cout << "Here comes a seg fault!" << std::endl;
	ref_bob.c = 10234; // BOOM!

	return 0;
}

litghost fucked around with this message at 16:16 on Jul 22, 2008

That Turkey Story
Mar 30, 2003

litghost posted:

I am sorry to say this completely wrong. C++ lets you do terrible terrible things sometimes:

No, your code is what's wrong. ref_bob's initialization has undefined behavior as does trying to access ref_bob2 after bob2 was deleted. There is no way to legally work with a null reference and it is safe for your compiler to rely on that fact. Null pointers on the other hand are perfectly fine and can legally be formed.

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.
I hate C++ so much.

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

litghost posted:

I am sorry to say this completely wrong. C++ lets you do terrible terrible things sometimes:

code:
	Aclass * bob = (Aclass*)0;
	Aclass & ref_bob = *bob;

Before you even touch ref_bob, you dereference of a null pointer, which is undefined behavior. You can't blame the language for anything that happens after you do something undefined. If your compiler happens to allow the operation to proceed and segfault on a reference later, that's fine, but that doesn't have anything to do with how references are defined to work in C++.


Edit: And as far as the heap corruption trick, references are guaranteed not to be null; they're not guaranteed to always be valid (try returning a reference to something on the stack for a similar effect).

Smackbilly fucked around with this message at 16:33 on Jul 22, 2008

litghost
May 26, 2004
Builder

Smackbilly posted:

Before you even touch ref_bob, you dereference of a null pointer, which is undefined behavior. You can't blame the language for anything that happens after you do something undefined. If your compiler happens to allow the operation to proceed and segfault on a reference later, that's fine, but that doesn't have anything to do with how references are defined to work in C++.

But the code compiles and runs (and dies horribly). My point was not that you should be able to do these thing, but that they are possible. You CAN have a reference to a NULL pointer, you can hold a reference to de-allocated memory. In short:

JoeNotCharles posted:

I hate C++ so much.

:edit:
I tested on both VC++ 2005 express and gcc version 3.4.4 (cygming special, gdc 0.12, using dmd 0.125). They both allow the NULL pointer to enter the reference. Seg fault occurs when you try to access the data.

litghost fucked around with this message at 16:46 on Jul 22, 2008

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

litghost posted:

But the code compiles and runs (and dies horribly). My point was not that you should be able to do these thing, but that they are possible. You CAN have a reference to a NULL pointer, you can hold a reference to de-allocated memory. In short:

Just because your code compiles and runs doesn't mean the code is valid C++. The C++ standard leaves a number of things "undefined", and if you do any of those things your code is no longer valid C++ and all bets are off. The canonical admonition is "undefined behavior can do anything, including doing nothing, crashing your program, or erasing your hard drive."

If anything your complaint is that your compiler is not smart enough to detect that what you have written is not C++ and yet attempts to compile it as C++ anyway.

litghost
May 26, 2004
Builder

Smackbilly posted:

Just because your code compiles and runs doesn't mean the code is valid C++. The C++ standard leaves a number of things "undefined", and if you do any of those things your code is no longer valid C++ and all bets are off. The canonical admonition is "undefined behavior can do anything, including doing nothing, crashing your program, or erasing your hard drive."

If anything your complaint is that your compiler is not smart enough to detect that what you have written is not C++ and yet attempts to compile it as C++ anyway.

WOOOSH. You have completely missed the point. My point is references are not guaranteed to be anything, just like pointers. They are not some run time protected concept or compile time protected either, they are syntactical sugar over raw memory access (maybe). Substituting references with pointers will only improve the syntax (good) not improve you ability to avoid memory faults (do not think this). Avoiding undefined behavior is hard work that must be achieved with your vigilance, not the compilers. Which is frankly dumb. So, again, my point is:

JoeNotCharles posted:

I hate C++ so much.

Avenging Dentist
Oct 1, 2005

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

litghost posted:

WOOOSH. You have completely missed the point. My point is references are not guaranteed to be anything, just like pointers.

And our point is that, yes, they are. That is what the standard dictates. If your compiler doesn't adhere to the standard, then you need to be careful of it; that's an issue with considerably more things than just null-references.

Besides that, the initial point was that references are semantically non-null. If you are using null references, you are being evil and deserve whatever bad things happen to you.

litghost
May 26, 2004
Builder

Avenging Dentist posted:

And our point is that, yes, they are. That is what the standard dictates. If your compiler doesn't adhere to the standard, -->then you need to be careful of it<--; that's an issue with considerably more things than just null-references.

Besides that, the initial point was that references are semantically non-null. If you are using null references, you are being evil and deserve whatever bad things happen to you.

This, right here, is my point. You need to be careful of your compiler. It will not protect you from doing stupid things, with a pointer or a reference. Or any other C++ caveat that is not obvious. In practice, with probably any compiler you can find, null references can exist. If you need a function that is absolutely bullet-proof, you cannot assume anything.

I am not advocating creating null references, only that such a thing can exist.

FYI C++ spec 8.3.2:

quote:

[Note:in particular,a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer, which causes undefined behavior.]
What compiler prevents non well-defined programs? Show me that, and I will agree that compiler would not allow null references to exist. But in general C++ compilers let you bring abominable things into existence (which then 9/10 crash).

litghost fucked around with this message at 18:03 on Jul 22, 2008

Vanadium
Jan 8, 2005

It's the C++ thread, not the your-C++-compiler thread. :mad:

litghost
May 26, 2004
Builder

Vanadium posted:

It's the C++ thread, not the your-C++-compiler thread. :mad:

Fair, but the realities of C++ mean that you will encounter bugs that are "against" the spec, but practically can exist. Putting you head in the ground and saying that they are impossible does not change the fact they can exist. Honestly I think a discussion of the caveats of the C++ spec would be enlightening. I am sure other people have run into fun things like virtual functions in constructors. I'll be quiet now, sorry for the derail.

more falafel please
Feb 26, 2005

forums poster

litghost posted:

WOOOSH. You have completely missed the point. My point is references are not guaranteed to be anything, just like pointers. They are not some run time protected concept or compile time protected either, they are syntactical sugar over raw memory access (maybe). Substituting references with pointers will only improve the syntax (good) not improve you ability to avoid memory faults (do not think this). Avoiding undefined behavior is hard work that must be achieved with your vigilance, not the compilers. Which is frankly dumb. So, again, my point is:

The point is that while
code:
char* p = 0;
do_some_crap(p);
is completely valid (and well-defined) C++,
code:
char* p = 0;
char& r = *p;
is NOT. Null pointers are meaningful, null references cannot exist in a well-formed C++ program.

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.

more falafel please posted:

The point is that while
code:
char* p = 0;
do_some_crap(p);
is completely valid (and well-defined) C++,
code:
char* p = 0;
char& r = *p;
is NOT. Null pointers are meaningful, null references cannot exist in a well-formed C++ program.

Isn't "well-formed" a compile-time concept? So how can it depend on the runtime value of p?

TSDK
Nov 24, 2003

I got a wooden uploading this one

JoeNotCharles posted:

Isn't "well-formed" a compile-time concept? So how can it depend on the runtime value of p?
Yes, 'well-formed' is as you say, a compile-time concept. It is impossible in general for a compiler to tell you that a C++ program contains no undefined behaviour (and so is well defined) because to do so you would need to solve the halting problem.

Vanadium
Jan 8, 2005

litghost posted:

Fair, but the realities of C++ mean that you will encounter bugs that are "against" the spec, but practically can exist. Putting you head in the ground and saying that they are impossible does not change the fact they can exist.

I just get a bit annoyed, for some reason, when some people blame C++ if their compiles do not detect the mistakes in their code. :(

Now, for something, completely different, what is up with enum foo { a = 1, b = 2 }; foo f = a; f |= b; not being legal? Am I supposed to roll my own "flags" class?

That Turkey Story
Mar 30, 2003

Vanadium posted:


Now, for something, completely different, what is up with enum foo { a = 1, b = 2 }; foo f = a; f |= b; not being legal? Am I supposed to roll my own "flags" class?

code:
foo& operator |=( foo& left, foo right )
{
  left = static_cast< foo >( left | right );
  return left;
}

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
May as well define operator '|' while you're at it.
code:
inline foo operator | (foo l, foo r){
  return static_cast<foo>(static_cast<int>(l) | r);
}
inline foo& operator |= (foo& l, foo r){
  return l = l | r;
}
edit: oops, fatal code omission

Mustach fucked around with this message at 23:19 on Jul 22, 2008

TSDK
Nov 24, 2003

I got a wooden uploading this one
I prefer the following syntax for the flag declarations:
code:
enum eMyFlags
{
    MyFlag1 = 1 << 0
    MyFlag2 = 1 << 1
    MyFlag3 = 1 << 2
    MyFlag4 = 1 << 3
};
It's a bit more self-documenting that way, and more easier to write than to keep shuffling powers of two lists around.

Importantly, don't forget to cast the flags to integer types within the operator| and operator& definitions, otherwise you'll end up with an infinite recursive function.

Doctor Chef
Nov 3, 2005
"Clothes Pigs?"
I really need help with this programming problem. The program I have to code for my class is one that will read the numbers from a file called "numbers.txt" then write only the even numbers to a new sequential access file named evenNumbers.txt. The only hint I had was to use the % modulus operator.

This is the contents of the numbers.txt file:

100
23
45
78
95
92
10
7
5
4
2
8


Then this is the contents of the c++ file I have created so far that I'm having trouble with:

code:
//Class Assignment - Sequential Access
//Writes the even numbers from a sequential access
//file to a new sequential access file


#include <fstream>
#include <iostream>

using std::ifstream;
using std::ofstream;
using std::ios;
using std::endl;
using namespace std;

int main()
{	
	int storeNumbers = 0;
	int evenNumbers = 0;

	ifstream inFile;
	inFile.open("numbers.txt");

	//determine if file was opened
	if (inFile.is_open())
	{
		cout << endl;
		inFile >> storeNumbers;
		inFile.ignore();

		while (!inFile.eof())
		{ 
			evenNumbers = (storeNumbers % 2 == 0);
		inFile >> storeNumbers;
		inFile.ignore();
		}
	}
	
	//close the file
	inFile.close();

	//write the even numbers to evenNumbers.txt


	ofstream outFile;
	outFile.open("evenNumbers.txt");

	//determine if file was opened
	if (outFile.is_open())
	{
		while (!outFile.eof())
		{
		outFile << evenNumbers << endl;
		}

	}

	//close that file
	outFile.close();


    return 0;
}   //end of main function
When I run the program it doesn't ever state to Press a key to quit or anything, it just blinks the cursor on the prompt window. I go to the folder I've saved the c++ file in and it does create the evenNumbers.txt, but it only outputs a continuous loop of 1's like this:

1
1
1
1
1

to the file.

Any help would be appreciated.

Entheogen
Aug 30, 2004

by Fragmaster
you need to store your numbers in an array not an int. int is for just one number that is represented with 4bytes usually. Also you are assigning evennumbers to store numbers % 2 before you even read store numbers from file. The reason it outputs only 1s is because you are only printing out one variable which never changes, and got set to 1 the last time you modified it. That is because the last number to be assigned to evennumber is 2 % 2 == 0 which is true or 1.

Also don't do while ( !outFile.eof() ) to print stuff to that file stream. You only need to check for that when you are reading it in.

oh and to catch errors, like whether files were succefully opened or not, you can just surround the whole thing with try catch block and catch std::exception & exc.

I am not sure if my code takes care of new line and carriage return characters for input. If you run into problems you can use .ignore function, but the way you should use it is
code:
if( ifs.peek() == '\n' || ifs.peek() == '\r' ) ifs.ignore();
that way you are only ignoring new line chars which you don't care for.

just do something like this. I use vector here which is STL class for dynamic arrays (they can be resized easily).

code:
#include <fstream>
#include <iostream>
#include <vector>

using namespace std;

int main()
{
    ifstream ifs( "input_numbers.txt" );
    vector<int> numb3rs;
    while( !ifs.eof() )
    {
         int numb3r;
         ifs>>numb3r;
         numb3rs.push_back( numb3r );
    }
    ofstream ofs( "output_even_numbers.txt" );
    for( int i = 0; i < numb3rs.size(); ++i )
    {
       if( numb3rs[i] % 2 == 0 ) ofs<<numb3rs[i]<<endl;
    }
    ifs.close();
    ofs.close();
}

Entheogen fucked around with this message at 02:23 on Jul 23, 2008

Doctor Chef
Nov 3, 2005
"Clothes Pigs?"
Is there a way to do this without vectors? We haven't gotten that far so do you know of a way strictly using arrays?

TheSleeper
Feb 20, 2003
Alternatively, you could just loop until EOF and if the current number % 2 is 0, add it to the output file. That way there is no need for an array or knowing how many numbers you should be prepared to deal with.

blorpy
Jan 5, 2005

TheSleeper posted:

Alternatively, you could just loop until EOF and if the current number % 2 is 0, add it to the output file. That way there is no need for an array or knowing how many numbers you should be prepared to deal with.

This is the correct way. Open both files, iterate through the input and drop the number into the output if it's even.

I would recommend asking for some tutoring from a TA or another student. Programming is very hard to grasp at first, and getting help from someone during the process can get you on the right path. It can also help clear up any misunderstandings so that they don't follow you any longer than they have to.

blorpy fucked around with this message at 02:43 on Jul 23, 2008

Doctor Chef
Nov 3, 2005
"Clothes Pigs?"
Can you give me a sample of what you two just said?

My book isn't very clear and I have a very very limited time to finish this one program. I appreciate all of the help.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
code:
ifstream input("foo.txt");
ifstream output("bar.txt");

string some_word;

input >> some_word;
output << "Here is a word: " << some_word << endl;

blorpy
Jan 5, 2005

Doctor Chef posted:

Can you give me a sample of what you two just said?

My book isn't very clear and I have a very very limited time to finish this one program. I appreciate all of the help.

I actually have no qualms with writing homework problems, since the burden of learning is still on the student. I'm going to modify your source a bit to basically do what I was saying. I'm not going to use anything you haven't, though. Just a bit of copy/paste.

code:
/Class Assignment - Sequential Access
//Writes the even numbers from a sequential access
//file to a new sequential access file


#include <fstream>
#include <iostream>

using std::ifstream;
using std::ofstream;
using std::ios;
using std::endl;
using namespace std;

int main()
{	
	int storeNumbers = 0;

	ifstream inFile;
	inFile.open("numbers.txt");
	
	ofstream outFile;
	outFile.open("evenNumbers.txt");

	//determine if file was opened
	if (inFile.is_open())
	{
		if(outFile.is_open())
		{
			cout << endl;
			inFile >> storeNumbers;
			inFile.ignore();

			while (!inFile.eof())
			{ 
				if(storeNumbers % 2 == 0)
				{
					outFile << storeNumbers << endl;
				}
				inFile >> storeNumbers;
				inFile.ignore();
			}
			outFile.close();
		}
		inFile.close();
	}


    return 0;
}   //end of main function
You were close. All I had to do was copy and paste to get this...

Doctor Chef
Nov 3, 2005
"Clothes Pigs?"
^^^ Thank you all very much for your help. Again, it's very much appreciated. I think I see where the problem was now.

Adbot
ADBOT LOVES YOU

TheSleeper
Feb 20, 2003

Chain Chomp posted:

I actually have no qualms with writing homework problems, since the burden of learning is still on the student.

No offense, but isn't it a whole lot better to at most provide a pseudocode solution?

Also, it doesn't really matter much in this case, but with your solution if, for some reason, it fails to open the input file but opens the output file just fine it will never close the output file.

The best solution would be to open the output file after testing to see if the input file was open.

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