Reputation: 339
I have a class holding a pointer. I have only included skeleton code here. The class constructor expects a string.
#include <iostream>
#include <string>
using namespace std;
class slice {
public:
slice(string s):
data_(s.data()),
size_(s.size()) {}
const string toString() {
string res(data_, data_+size_);
return res;
}
private:
const char* data_;
const size_t size_;
};
int main() {
slice a{"foo"};
slice b{"bar"};
cout << a.toString() << endl;
cout << b.toString() << endl;
}
The output of this program is:
$ g++ test.cpp && ./a.out
bar
bar
I am expecting
foo
bar
What is going on here? How is the pointer held by object a being overwritten?
Upvotes: 4
Views: 153
Reputation: 3956
The std::string
objects calls its destructor std::~string()
when it goes out of scope.
slice(string s) : data_(s.data()), size_(s.size()) {
// After this function is called, the string goes out of scope and s.data() is deallocated by the destructor.
// Leaving gibberish value inside of 'data_' member
}
Afterwards, when you actually print the value, data_
was already destroyed by then and what you do with it afterwards results in Undefined Behavior (It means the behavior of the program when outputting the string can be anything, thus the term undefined).
Since this question has already been answered. I might as well give a reasonable solution.
Solution: Create a copy of what the string is holding temporarily inside your class and destroy it when your class goes out of scope:
Example:
class slice {
public:
slice(string s):
size_(s.size()) {
// Dynamically allocate a new string so that it doesn't get deleted when it goes out of scope
data_ = new char[s.size()];
// Copy the data into the newly allocated string
s.copy(data_, s.size());
}
slice(const slice&) = default; // Copy constructor
slice(slice&&) = default; // Move constructor
// Destructor
~slice() {
delete[] data_;
}
const string toString() {
// Now 'data_' retains its value even after the string is destroyed
string res(data_, data_+size_);
return res;
}
private:
char* data_;
const size_t size_;
};
Upvotes: 0
Reputation: 2598
a and b are being created from temporary string objects. When those string objects are destroyed by the end of the statement, they deallocate their memory, and the underlying char* pointing to where the characters were becomes invalid. You can't usually use a char* taken from a string like this.
Upvotes: 0
Reputation: 85541
What is going on here? How is the pointer held by object a being overwritten?
You are experiencing undefined behavior.
slice(string s):
data_(s.data()),
size_(s.size()) {}
Here string s
is a copy of the input string and lives for the duration of the constructor. Hence s.data()
dangles after the constructor is finished.
Upvotes: 5