I have an extraction operator being used for a class that has a char* member 'name'. Here is my code from my main driver:
Player tempPlayer;
for(int i=0;i<4;i++){
fin >> tempPlayer;
}
I then go on to do something with that extracted player (which is irrelevant), but the issue is that each time the extraction operator is used, something strange occurs. Here is the definition of the operator:
ifstream& operator>>(ifstream& fin, Player& currentPlayer){
char* temp = new char[50];
char tempChar;
fin >> temp;
// importing from a file that contains names of about 6 characters each
stringCopy(currentPlayer.name, temp);
delete[] temp;
temp = NULL;
return fin;
}
stringCopy body:
void stringCopy(char *destPtr, const char *sourcePtr){
while(*sourcePtr!='\0'){
*destPtr = *sourcePtr;
destPtr++;
sourcePtr++;
}
*destPtr='\0';
}
I have been debugging by printing out the memory addresses being used for temp and the name.
The FIRST time the extraction operator is called, the player's name and the temp array have different memory addresses, which is what should happen. Then temp is then deleted and set to NULL, which I confirmed by printing the address (and getting '0'), and the address of the player's name remains after the function has returned.
However, on subsequent calls, the address of both temp AND the player's name become identical to the address of the first player's name. The name address SHOULD be the same, as it is the same object that is just being overwritten, but why is temp getting the SAME address as "name" if it is allocated with the new char[] keywords?
Here is some code I used when debugging:
Along each step of the way in the body of the operator:
cout << "temp address followed by name address: " << (void*)temp << " " << (void*)(currentPlayer.name) << endl;
In the main driver:
cout << "player " << i+1 << " has been extracted with name address " << (void*)(tempPlayer.name) << endl;
Here is the Player constructor:
Player::Player(){
name = new char[50];
stringCopy(name,"name");
ID = new int[5];
}
Excluding irrelevant data members, here is Player definition:
class Player{
public:
char* name;
};
When you delete[] something you've new[]ed, the standard library is allowed to reuse that memory. It's not surprising, therefore, that temp ends up getting the same address again and again. That is expected behavior and not a problem in and of itself.
The real problem is that in your "driver" code (a bit of code you haven't shown us), you have a shallow copy of tempPlayer somewhere. This copies the pointer to name, without allocating new storage. When that copy gets deleted, the destructor for Player deletes name in this shallow copy, releasing name to the heap.
Now the original is left pointing to freed memory. A future call to your operator>> then allocates this now supposedly-free memory. Oops!
Your short term fix was to remove the shallow copy. The long term, correct fix is to implement proper copy and copy-assignment constructors, as per the "Rule of 3" ( http://en.wikipedia.org/wiki/Rule_of_three_%28C++_programming%29 ), or if you want to be really C++11 friendly, the rule-of-5. (Same link.)
Alternately, you could consider making the copy and copy-assignment constructors private, which would prevent unwanted copies of these objects. (Some hints here: What's the most reliable way to prohibit a copy constructor in C++? )
Related
How can I simply pass this line of text to a member function? That's all I'm asking... There is a member function called Student:Populate(std::string) that I would like to connect the particular instance of Student to the data of the specific file line... I don't know how to do it syntactically.
it's for a school assignment so I must use manual allocation of new/delete, no smart pointers and no vectors so just ruling those out off the bat.
int main(){
std::stringstream stream;
std::string current;
Student temp;
Student *database = new Student[50];
inFile.open("students.dat", std::ifstream::in);
outFile.open("FullReport.txt",std::ofstream::out);
while(getline(inFile,current)){
for(int i = 0; i < 50; i++){
Student[i] = new Student(current); //this line doesn't work when it's compiled
outFile << Student[i] <<std::endl; //neither does this one
//there is a Student Populate(std::string); function I would like to pass the data to... How can I do that?
}
inFile.close();
outFile.close();
}
COMPILER ERRORS:
error: expected unqualified-id before ‘[’ token
Student[i] = new Student(current);
^
main.cpp:26:27: error: expected primary-expression before ‘[’ token
outFile << Student[i] <
So, a couple of things.
First, there is no Student[i]. Student is a class name. Classes don't have a way to access from operator[] unless you overload it (probably a future topic in your class) and even then it probably won't be static, meaning that Student[i] has no real meaning.
There is, however a database[i], which is probably what you want.
Secondly, database[i] is not a pointer, so there is no reason to allocate with new. You already did that above with the line Student *database = new Student[50];, so even something like database[i] = new Student(current); is pointless. Instead, try this:
database[i] = Student(current);
This assigns a new instance of Student to database[i]. No new needed here.
Finally, note that this would assign a new instance of Student to database[i], meaning it will call a constructor. If you don't have a constructor that accepts a std::string, that won't compile. It also won't call Populate() either.
If you want to call Student::Populate(), to do that you need to call it on an instance of the object. Like this:
database[i].Populate(current);
I hope that's what you were asking.
P. S. I should also mention that as a general rule, you shouldn't use new. The Standard Template Library is far better.
Of course, most school assignments don't allow this, so sometimes you have to use new. But I guess I should still mention it.
Lets go thought this bit by bit
int main()
{
std::stringstream stream;
stream's not used here. For now let's get rid of it. It'll come back again later, though.
std::string current;
Student temp;
Student *database = new Student[50];
This creates 50 Students.
inFile.open("students.dat", std::ifstream::in);
outFile.open("FullReport.txt",std::ofstream::out);
Opens the files. Can be done a bit better, but right.
while(getline(inFile,current))
{
Perfect. Got a line from the file.
for(int i = 0; i < 50; i++)
With this one line from the file, do the same thing 50 times. Ask your Rubber duck if it thinks this makes sense.
{
Student[i] = new Student(current);
Student is a type, not a variable. You can't store in a type. Odds are you meant to use database, but it is an array of Students, and new Student(current) provides pointers to Students.
outFile << Student[i] <<std::endl;
}
inFile.close();
outFile.close();
Closing the files too soon. You haven't read all of the students yet.
}
}
How to fix:
int main()
{
std::string current;
Student **database = new Student*[50];
database is an array of 50 pointers to Students, al ready to accept new Students. But more on this later.
std::ifstream inFile("students.dat");
std::ofstream outFile("FullReport.txt");
If we define the file streams here and specify the direction (ifstream, ofstream) we don't need to specify it again. Plus we can open the file right in the constructor. Who needs messy calls to open? Finally because the files are local variables they will automatically be destroyed and close at the end of the function. No need for a messy call to close. (See What is meant by Resource Acquisition is Initialization (RAII)? for more on this concept) Code you don't have to write doesn't have bugs. And if it somehow does, they aren't your fault.
int count = 0;
count is a much more descriptive name than i
while (std::getline(inFile, current))
{
nothing changed here. This is fantastic. There is a famous question on Stack Overflow that is famous because of how many people get this wrong. Kudos. You got it right.
database[count] = new Student(current);
new Student allocated and added to database. More on this later.
outFile << *database[count] << std::endl;
And written to output file. Note the * to dereference the pointer and get the value pointed at so it can be printed with a regular << operator (which you have to provide, by the way). Without the * the program will print out the contents of the pointer: An address.
count++;
}
}
And one more time without all of the explanation for easy code reading
int main()
{
std::string current;
Student **database = new Student*[50];
std::ifstream inFile("students.dat");
std::ofstream outFile("FullReport.txt");
int count = 0;
while (std::getline(inFile, current))
{
database[count] = new Student(current);
outFile << *database[count] << std::endl;
count++;
}
}
OK it's later. You don't want
Student **database = new Student*[50];
It's pretty gross for several reasons.
Modern computers are fantastic at thinking in straight lines. If the data is on one nice straight line they can read ahead and have the data ready for you before you need it. Arrays of data are awesome. Arrays of pointer to data prevent the computer from getting up speed. It reads one Student, then it has to look up another pointer to find the next Student. This can be slow. Cripplingly slow. With an array of Students while you are using Student 0, the computer is loading (or has already loaded when it loaded Student 0) the next bunch of Students.
Every dynamic allocation has a cost. The program has to ask the OS for a block of memory. The OS has to find one. This can be expensive. It's much better to get one big block of memory and divvy it up into an array of Students.
Each dynamic allocation has to be put away. Allocate 50 Students and you need to have code that puts away 50 Students. Allocate an Array of Students, you put away one Array of Students
You want something more like
int main()
{
std::string current;
Student *database = new Student[50];
std::ifstream inFile("students.dat");
std::ofstream outFile("FullReport.txt");
int count = 0;
while (std::getline(inFile, current))
{
database[count] = Student(current);
outFile << *database[count] << std::endl;
count++;
}
}
And of course what you really want is
int main()
{
std::string current;
std::vector<Student> database;
std::ifstream inFile("students.dat");
std::ofstream outFile("FullReport.txt");
while (std::getline(inFile, current))
{
database.emplace_back(current);
outFile << database.back() << std::endl;
count++;
}
}
But this will get a nice round zero from the instructor. First rule of school is give the teacher what they want and pass the course. Second rule is read a bunch of other stuff to learn what you weren't taught so you won't be useless once you graduate.
I am just starting C++ and I can't understand how my code works:
Ok I allocate memory, but at the time of the allocation nobody knows the size of the memory to be allocated. But still the code works.
How much memory is allocated? How the compiler knows how much memory I will need?
EDIT:
Sorry if my question was not clear. Let me please try clarify it. So I dynamically allocate some memory in the heap by using my pointer. But since there is no text in the sting variable, in my opinion it is quite difficult to know how much text (bytes) I will enter via getline.
I tried asking the size of two different text literals, and yes they are different in size.
sizeof("") // is 1 (because of the ending 0 maybe?)
sizeof("sometext") // is 9
But for the string: the sizeof gives me 4 both times. It's clear that the sizeof() gives me the length of the pointer pointing to the string.
How can I allocate memory? If I allocate memory for a new string, only allocates to a pointer pointing to the memory address of the first character in the string?
Obviously the characters I enter must be stored somewhere. And I first allocate the memory, and then I load some text into it.
Edit 2: make the edited code to look code, not plain text.
//Edit:
string a,b = "sometext";
cout << sizeof(a) << endl; //4
cout << sizeof(b); //4
//--------------------------------------------------------
#include <iostream>
#include <string>
#include <exception>
using namespace std;
int main()
{
//Defining struct
struct musicCD
{
string artist, title; // artist of the CD
};
//Memory allocation
musicCD *ptr;
try{ptr = new musicCD;}
catch(bad_alloc){cerr << "Out of memory :(";return -1;}
catch(...){cerr << "Something bad happened :O !";return -1;
}
//Get the data to store:
cout << "Please enter the data for the CD!' " << endl;
cout << "Please enter the artist: ";getline(cin, ptr->artist); cout << endl;
//Write out the data
cout << "The data entered: " << endl;
cout << "The artist performing is: \t" << ptr->artist << endl;
delete ptr;
return 0;
}
It seems like you are confused about how std::string, or any dynamic container, handles the fact that it's memory requirements are not predetermined. std::string for example does not store it's character data internally. Simply put, it contains a pointer that points to another dynamic allocated buffer which contains the actual data. std::string has constructors, a destructor and assignment operators that automatically manage the extra buffer, which contains the actual character data. This including reallocating, copying the data, updating the internal pointer and freeing the previous buffer when extra storage is needed. The size of the buffer that contains the actual data does not count towards the size of std::string, only the pointer to it does. Every instance of std::string, throughout it's lifetime, only directly contains a constant number of members which all have constant sizes. In c++ all types have a compile time constant size.
See Rule of five for a simplified implementation of string showing how it works. The size of the class rule_of_five from this example is simply the size of char* regardless of the content of the buffer pointed to by this pointer. The actual buffer is allocated later, during or after construction, which is after the initial allocation for the object itself has already finished.
Edit: There are some cases where a string can store it's character data internally when dealing with very short strings. This is an optimization not generally seen in other containers. See this answer.
This question already has answers here:
C++ delete - It deletes my objects but I can still access the data?
(13 answers)
Closed 3 years ago.
I have to classes, one Employee class and one BankAccount class, the employee class has the BankAccount class as a private variable pointer.
This is what I am trying to do:
I need to set up all the BankAccounts in each Employee with values
then I delete all BankAccounts for every Employee at the end of the function.
I use a member function setter in Employee to set up the BankAccount pointer. BankAccount has one private variable and that is amount. Later I call delete on a pointer that should point to each BankAccount's memory address. After I call print to see the values of the bank for each Employee and it is still printing values for each BankAccount
If I call delete shouldn't the memory on heap be delete and when print is called not output anything for BankAccount?
Here is the code:
vector<Employee*> employees;
//get employee full name & salary and return
employees.push_back(get_employee_info());
//setup their bank account
setup_bank(employees);
//make temp pointer to store bank memory address
BankAccount * tempBankPtr;
for (int i =0; i < employees.size(); i++) {
tempBankPtr =employees[i]->get_bank();
delete tempBankPtr // delete the heap object that pointer is pointing at
}
//print values
for (int i =0; i< employees.size(); i++) {
employees[i]->print();
}
code for print
void Employee:: print() const {
cout << "First name is: " << firstName << "\n";
cout << "Last name is: " << lastName << "\n";
BankAccount* bankholder = NULL;
bankholder = get_bank();
if(bankholder != NULL)
cout << "Account Balance is: " << get_bank()->get_amount() << "\n"; //prints values
}
getter for bank
BankAccount* Employee::get_bank() const{
return bank;
}
this is called in setup_bank
void Employee::set_bank(Employee* e, double amount){
bank = new BankAccount(amount);
}
If I call delete shouldn't the memory on heap be delete and when print is called not output anything for BankAccount?
No.
Deleting the object at that location in memory means it does not exist any more, so you're not allowed to access it.
It does not mean your program will magically print "nothingness" to protect you from this mistake.
Your program therefore has undefined behaviour; you must make sure you do not dereference an invalid pointer!
A very nice explanation of how free works.
When you call delete on the pointer and unlike as it has been suggested above you should only expect the following
Execute the destructor
The memory is not set to zero or any other magical value, since that is a very very expensive operation. When free is going to be called and if furthermore this will cause a call to sbrk is largely implementation dependent. The latter returns memory to the operating system.
For example AIX is well known to have a quite complex mechanism for memory management. What you should expect is that actually the block of memory will be marked as reallocatable , and new objects might overwrite your after the address pointed. Until this happens, you old staff are most probably still there.
Furthermore unlike stated before you can very well access it for as long as the data segment has not been reduced, and actually the object still exists , it is just that only you know about it.
That is why in this case you do not get SIGSEGV as you would expect. You probably get it later when you allocate something and the addressing a pointer in that memory area executes arbitrary code.
Accessing a delete pointer is undefined behavior and deleting it a second time is even more dangerous. To alleviate the situation there are many techniques , the most simple being encapsulation and deleting the pointer on the class destructor. You should set the pointer to nullptr.
Simplicity stops here, since you have to apply the rule of three (and a half ) . Thus it is better to work with shared or unique pointer provided by c++11 , and ignore these issues for now.
I am working on a small console game on my free time and have come across a bug I can't seem to fix no matter what I try. I have tried a lot of different things with the pointers so this is just the latest version of my code. I have been searching around and a few questions other's have asked indicated I may be experiencing a memory leak, or that I am reading values from beyond my arrays (don't understand how). However, those questions have been solved without leaving me any hints as to what is wrong with my code.
Basically, I have a function called int * spendAttribute(int point);
Since anything created in that function is out of scope in my main() I want to take 6 int out of that function, and bring them into my main().
I thought "hey why not use a pointer!" The function is supposed to return a pointer to an array created during the function, and paste it to another pointer created in main(), this has worked once before in my main(), but now it's not working and I have no clue why.
int * spendAttribute(int point)
{
string choice;
int hp,hpT,endur,endurT,dmg,dmgT,armor,armorT,agility,agilityT,evade,evadeT;
while(condition)
{
//do a bunch of junk ....
}
int stats[6] = {hp,endur,dmg,armor,agility,evade};
//some cout testing to see if values are correct (they are)
int* p_stats = new int [6]; //create a block of 6
p_stats = &stats[0]; //point to the first value of stats array
return p_stats; //return pointer
delete [] p_stats; //delete blocks
}
Note: I have tried without deleting the blocks and it still does not work. I tried this since I read that it might be a memory leak.I have tried it without using new at all.
main()
{
//.... some junk
while(main game loop)
{
int * pointer;
cout << "*************** Enter 'begin' to commence ****************** " << endl ;
cout << "*************** Enter 'spend' to use new attribute points ** " << endl ;
cin >> beginChoice; //declared before while loop
if(beginChoice == "spend")
{
cout << "total attributes: " << Bryan.returnAttribute() << endl ;
pointer = spendAttribute(Bryan.returnAttribute()); //copy pointer
cout << "TEST: " << endl ;
cout << pointer[0] << endl ; //out put is a bunch of random numbers..
cout << pointer[1] << endl ;
cout << pointer[2] << endl ;
cout << pointer[3] << endl ;
cout << pointer[4] << endl ;
cout << pointer[5] << endl ; //SOME DAMN BUG HERE
Bryan.addMaxHp(pointer[0]);
Bryan.addEndurance(pointer[0]);
Bryan.addDmg(pointer[0]);
Bryan.addArmor(pointer[0]);
Bryan.addAgility(pointer[0]);
Bryan.addEvasion(pointer[0]);
//after this character ends up having some ridiculous stats like -564553535%
//evasion or 9879967856 armor...
}
}
}
This method of transferring the array over to main worked for me before in this exact file, so I don't know exactly how I am getting these errors or what's causing them. I have even tried deleting the previous pointer used to see if thats what was causing it but it wasn't.
Please Halp.
Because you return a pointer to a local variable, and when that local variable goes out of scope you have a stray pointer.
And no, your allocation doesn't help, as you reassign the pointer to point to the local array, instead of copying into the allocated area. This of course means you also have a memory leak.
Regarding memory leak, you will still have a memory leak even when you fix the above problem. The reason being that you return from the function before you delete[] the pointer, and return returns from the function immediately, all code after a return statement is dead code. That means every time you call the function, it will allocate new memory which will never be free'd.
There are two obvious solutions to both the problems above: One is to allocate memory, copy the array into the allocated memory, and returning the pointer, and in the caller you do delete[] on the pointer.
The second solution is to pass in an array as argument, and use that instead of the local stats array.
p_stats is a pointer to int.
First you assign it to a newly allocated place in memory.
Then you move the pointer to point to local storage and return that. My guess is that you really wanted to return stats. Your options are:
Returns std::vector< int >. Probably simplest.
Modify your function to take a buffer to data and a length and fill it in.
Return std::array if available and you know it will be a fixed size of 6.
Although you could copy the data into p_stats then return that, it is not ideal because the calling function is then responsible to delete the data later.
If the fields have different meanings, you might want to create a struct with meaningful names for the values, and get your function to return that struct. e.g.
struct SpendAttribute // in header
{
int hp;
int endur;
int dmg;
int armor;
int agility:
int evade
};
SpendAttribute spendAttribute( int point )
{
SpendAttribute res;
// enter code here
return res;
}
There is a final option of putting the data into a smart-pointer like boost::shared_array<int> or you can use shared_ptr with an array-deleter.
For now, just return std::vector<int>
I'm reading through an example in primer and something which it talks about is not happening. Specifically, any implicit shallow copy is supposed to copy over the address of a pointer, not just the value of what is being pointed to (thus the same memory address). However, each of the pos properties are pointing to two different memory addresses (so I am able to change the value of one without affecting the other). What am I doing wrong?
Header
#include "stdafx.h"
#include <iostream>
class Yak
{
public:
int hour;
char * pos;
const Yak & toz(const Yak & yk);
Yak();
};
END HEADER
using namespace std;
const Yak & Yak:: toz(const Yak & yk)
{
return *this;
}
Yak::Yak()
{
pos = new char[20];
}
int _tmain(int argc, _TCHAR* argv[])
{
Yak tom;
tom.pos="Hi";
Yak blak = tom.toz(tom);
cout << &blak.pos << endl;
cout << &tom.pos << endl;
system("pause");
return 0;
}
You're printing the addresses of the pointers, not the address of the string they're pointing to:
cout << &blak.pos << endl;
cout << &tom.pos << endl;
They are two different pointers, so their addresses differ. However, they point to the same string:
cout << static_cast<void*>(blak.pos) << endl;
cout << static_cast<void*>(tom.pos) << endl;
(Note that cast static_cast<void*>(tom.pos). As Aaron pointed out in a comment, it is necessary because when outputting a char* will through operator<<, the stream library will assume the character pointed to to be the first character of a zero-terminated string. Outputting a void*, OTOH, will output the address.)
Note that there is more wrong with your code. Here
Yak tom;
You are creating a new object. Its constructor allocates 20 characters, and stores their address in tom.pos. In the very next line
tom.pos="Hi";
you are assigning the address of a string literal to tom.pos, thereby discarding the address of the bytes you allocated, effectively leaking that memory.
Also note that Yak has no destructor, so even if you don't discard the 20 characters that way, when tom goes out of scope, tom.pos will be destroyed and thus the address of those 20 bytes lost.
However, due to your missing copy constructor, when you copy a Yak object, you end up with two of them having their pos element pointing to the same allocated memory. When they go out of scope, they'd both try to delete that memory, which is fatal.
To cut this short: Use std::string. It's much easier. Get a grip on the basics, using safe features of the language like the std::string, the containers of the stdandard library, smart pointers. Once you feel sure with these, tackle manual memory management.
However, keep in mind that I, doing C++ for about 15 years, consider manual resource management (memory is but one resource) error-prone and try to avoid it. If I have to do it, I hide each resource behind an object managing it - effectively falling back to automatic memory management. :)
Which "primer" is this you're reading? Lippmann's C++ Primer? If so, which edition? I'd be surprised if a recent edition of Lippmann's book would let you lose onto dynamic memory without first showing your the tools to tackle this and how to use them.
Unless i'm missing something, it seems you are printing out the address of variable pos, but not the address to which they both point to. The addresses of both pos are different, but the pointers should be the same.
The code does not make a lot of sense.
The toz method takes a Yak but does nothing with it. Why? In fact, what is toz supposed to do, anyway?
tom.pos = "Hi" does not copy Hi into the new char[20] array that you allocate in the constructor. Instead it replaces the pos pointer with a pointer to a static const char array containing "Hi\0". You would need to use strcpy.
Your code has a memory leak in it. You are allocating 20 characters on construction and have pos point to the allocated memory. However you are then pointing pos at the memory containing "Hi" without deleting the memory first.
In any case, pos is a member variable of type char *. Each instance of Yak is going to have its own unique pos. Because pos is a pointer, however, it's possible that they are pointing to the same block of memory (and this is the case in your example).
What you are printing out is the address of the pos variable which is of type char *, and not the address of the memory it is pointing to, which is of type char. Remember that a pointer is a variable like any other, it has an address and a value (and that value, in the case of a pointer, is an address).
If you want blak to be a shallow copy of tom, try the following instead of using your function toz:
Yak *blak = &tom;
// Note the use of -> ; also, &blak->pos will work
cout << &(blak->pos) << endl;
cout << &tom.pos << endl;
Now, blak merely points to tom --- it has nothing else associated with it.
Also, there are two other issues with your code:
pos = new char[20];
You are allocating memory here which has not been freed when you're done with the Yak object --- this will lead to memory leaks (unless you plan to free it elsewhere). If the use of pos ends with the use of the Yak object it's associated with (e.g.tom) then I recommend adding delete pos; to the destructor of Yak. Or as sbi suggested, use std::string.
tom.pos = "Hi";
You're assigning it to a string literal. This means that pos will be stuck to Hi which is actually a read-only section in memory. You cannot change the string stored in pos, so I don't think this what you intended. Therefore, allocating 20 bytes in the beginning to pos seems pointless.
Again, I recommend using string.