I have this piece of code that prints the content of a directory using Boost.Filesystem:
class Shell {
private:
const string& command;
const path& firstPath;
const path& secondPath;
public:
// constructor
Shell(const string& _command, const path& _firstPath, const path& _secondPath = path()): command(_command), firstPath(_firstPath), secondPath(_secondPath) {}
//destructor
~Shell() {}
//execute commands
void executeCommand()
{
if(command.compare("ls"))
{
ls();
}
}
void ls()
{
if(exists(firstPath))
{
vector<path> vecPath;
copy(directory_iterator(firstPath), directory_iterator(), back_inserter(vecPath));
sort(vecPath.begin(), vecPath.end());
for(vector<path>::iterator it = vecPath.begin(); it != vecPath.end(); ++it)
{
cout << *it << endl;
}
}
}
};
int main(int argc, char** argv)
{
path Path = "c:\\workspace";
Shell shell("ls", Path); // GOOD
// Shell shell("ls", "c:\\workspace"); BAD creates temporary !!
shell.executeCommand();
}
If I send my second argument direclty as a const char* I know that it will create a temporary and my constructor argument will only be visible in the constructor, then its lost, because of the reference to temporary.
My question is, why isnt the same thing happening to the first argument, the string, because I am sending him also as a const char* directly, but the value isnt lost outside of the constructor ?
Shell shell("ls", Path); // BAD - just happens to work as you expected.
Undefined Behavior - Anything can happen, including acting like you expect. The memory allocated by the temporary just happened to not be overwritten in your case.
std::string *ref;
{
std::string tmp("temp");
ref = &ref; // risky, need to keep lifetime of tmp in mind
const char* const rawptr = ref->c_str(); // equivalent to tmp.c_str()
tmp = "altered"; // *ref also modified, rawptr completely invalid
}
// *ref _and_ rawptr completely invalid.
Is there a specific reason why you store references instead of copies?
By changing your class from
class Shell {
private:
const string& command;
const path& firstPath;
const path& secondPath;
...
to
class Shell {
private:
const string command;
const path firstPath;
const path secondPath;
...
you can avoid lot's of your problems and both cases will be correct.
Why this is the case you can see in the answer of sehe
Related
I have 10 char* properties of my class called Car,what is the best way to write the setters of these 10 char* properties? One way is to directly set the value in it :
void Car<T>::setKey(const char* toCopyKey)
{
delete[] key;
int length=strlen(toCopyKey);
key=new char[length+1];
strcpy(key,toCopyKey);
}
and do this 10 times ,other solution I thought of , is to make a function that creates a copy of the passed char* and then assigns it in the setter :
char* Car<T>::copyString(const char* s)
{
int length=strlen(s);
char* property=new char[length+1];
strcpy(property,s);
return property;
}
and use the copyString method in every setter like this :
void Car<T>::setModel(const char* toCopyModel)
{
delete[] model;
model=copyString(toCopyModel);
}
But I was wondering if this second solution is correct and if there is a better way to do this copying?I cannot use std::string and vector.
I guess this is an assignment of some C++ course or tutorial, because otherwise I would recommend to question the whole design.
In general, I would learn as early as possible to not do manual memory management at all and use C++ standard library smart pointers. This relieves you from the burden to write destructors, copy|move-assignment and copy|move constructors.
In your example, you could use std::unique_ptr<char[]> to hold the string data. This is also exception safe and prevents memory leaks. Creation of the unique_ptr<char[]> objects can be centralized in a helper method.
class Car {
private:
std::unique_ptr<char[]> model;
std::unique_ptr<char[]> key;
static std::unique_ptr<char[]> copyString(char const* prop) {
auto const len = std::strlen(prop);
auto p = std::make_unique<char[]>(len+1);
std::copy(prop, prop + len, p.get());
p[len] = '\0';
return p;
}
public:
void setModel(char const* newModel) {
model = copyString(newModel);
}
void setKey(char const* k) {
key = copyString(k);
}
char const* getModel() const {
return model.get();
}
};
If you don't know them, I would recommend to read about the rule of zero.
You can combine your two methods by using a reference parameter:
static void Car<T>::setStringProp(char *&prop, const char *toCopyString) {
delete[] prop;
prop = new char[strlen(toCopyString)+1];
strcpy(prop, toCopyString);
}
void Car<T>::setModel(const char *toCopyModel) {
setStringProp(model, toCopyModel);
}
And make sure that your constructor initializes all the properties to NULL before calling the setters, because delete[] prop requires that it be an initialized pointer.
Car<T>::Car<T>(const char *model, const char *key, ...): model(nullptr), key(nullptr), ... {
setModel(model);
setKey(key);
...
}
I have a class IStream2:
class IStream2 {
private:
char* fn;
public:
IStream2(char* filename);
char* get_filename();
};
IStream2::IStream2(char *filename) {
strcpy(fn, filename);
}
char * IStream2::get_filename() {
return fn;
}
And here is the main code:
vector<IStream2> istreams;
char fn[] = "file1.txt";
IStream2 reader2 = IStream2(fn);
istreams.push_back(reader2);
char fn2[] = "file2.txt";
IStream2 reader3 = IStream2(fn2);
istreams.push_back(reader3);
cout << istreams[0].get_filename() << endl;
It prints file2.txt but I expected file1.txt.
I know that I should use string but I would like to resolve this problem.
IStream2::IStream2(char *filename) {
strcpy(fn, filename);
}
Allocates no storage for fn. strcpy(fn, filename); invokes undefined behaviour writing into whatever storage fn points at, and after that all bets are off. The program could do anything.
The right answer is to use std::string
class IStream2 {
private:
std::string fn;
public:
IStream2(const char* filename); // note const. if not modifying a passed rference,
// mark it const. The compiler can make optimizations
// and can catch mistakes for you
// also the function can now receive string literals
const char* get_filename(); // another const this is because a string won't
// easily give you a non const pointer
}; <-- note the added ;
IStream2::IStream2(const char *filename): fn(filename) {
}
const char * IStream2::get_filename() {
return fn.c_str(); // get the char array from the string
}
But I suspect this is an exercise in writing C with Classes, so back into the stone ages we go. This is a LOT more work because we have to manage all of the memory ourselves. For example, We need to observe the Rule of Three. What is The Rule of Three?
Sigh.
class IStream2 {
private:
char* fn;
public:
IStream2(const char* filename); // note const char *
~IStream2(); // need destructor to clean up fn. This means we need to
// comply with the Rule of Three
IStream2(const IStream2 & src); // copy constructor
IStream2 & operator=(IStream2 src); // assignment operator
char* get_filename(); // Note: by returning a non const pointer here we
// allow the caller to tamper with the contents of
// fn and even delete it. This defeats the point
// of declaring fn private, so avoid doing this.
};
IStream2::IStream2(const char *filename) {
fn = new char[strlen(filename) +1]; // allocate storage.
// The +1 is to hold the string's NULL terminator
strcpy(fn, filename);
}
// implement copy constructor
IStream2::IStream2(const IStream2 & src) {
fn = new char[strlen(src.fn) +1];
strcpy(fn, src.fn);
}
// implement destructor
IStream2::~IStream2()
{
delete[] fn;
}
// implement assignment operator. Using Copy And Swap Idiom
IStream2 & IStream2::operator=(IStream2 src)
{
std::swap(fn, src.fn);
return *this;
}
char * IStream2::get_filename() {
return fn;
}
int main()
{
vector<IStream2> istreams;
const char* fn = "file1.txt"; // note const char *. string literals may be
// read-only memory and can't be changed
IStream2 reader2 = IStream2(fn);
istreams.push_back(reader2);
const char* fn2 = "file2.txt"; // and again const char *
IStream2 reader3 = IStream2(fn2);
istreams.push_back(reader3);
cout << istreams[0].get_filename() << endl;
return 0;
}
Since we are wresting with dinosaurs, I won't bother with the Rule of Five and move operations, but see how much more annoying it is to have to do this the wrong way?
More on Copy And Swap Idiom
I have this class MyClass that, most often, is created by parsing a string. I cannot trust that this string is always correct and therefore I do not want to put the parsing in the constructor. Hence, I have created a static parsing function that returns true if the string is valid and false if it is invalid. See below:
class MyClass
{
private:
Type1 m_memberA;
Type2 m_memberB;
public:
MyClass(const Type1& parameterA, const Type2& parameterB)
: m_memberA(parameterA), m_memberB(paramterB)
static bool parse(const std::string& input, MyClass * result)
{
Type1 paramA;
Type2 paramB;
//Parse input and get values for paramA and paramB.
//Return false if the input is invalid.
MyClass temp(paramA, paramB)
*result = temp;
return true;
}
}
My intent was to use it as follows:
void myFunction(const std::string& input)
{
MyClass * myObject = NULL;
if(MyClass::parse(input, myObject))
{
//Use myObject for something
}
else
{
//Log invalid input string
}
}
Now, this crashes at run time. And I figured that is because I am trying to de-reference a NULL-pointer, which obviously doesn't work. How can I fix this?
You need to pass either a pointer-to-pointer to the function or a pointer reference and allocate with new:
static bool parse(const std::string& input, MyClass *& result)
{
// ......
result = new MyClass(paramA, paramB)
return true;
}
I have implemented a class string, similar to std::string one.
I have a problem when the destructor is called: the field length has the length of the characters allocated in field.
This is the class:
class indexException:public std::exception
{
public:
virtual const char* what()
{
return "Index is either too long, or negative";
}
};
class string
{
public:
static const unsigned int length_max=100;
string(const char* field=NULL)
{
if(field!=NULL)
{
const unsigned int length=strlen(field);
this->field=new char[length+1];
this->length=length;
for(unsigned int i=0;i<=length;i++)
this->field[i]=field[i];
}
else
{
this->field=NULL;
length=0;
}
}
string(string& str)
{
string(str.field);
}
~string()
{
if(length>0)
delete field;
}
char& operator[] (int i) const throw()
{
try
{
if(i<0 || i>=(int)length)
throw indexException();
}
catch(indexException& e)
{
std::cerr << e.what() << std::endl;
}
return field[i];
}
string& operator=(const char* field)
{
const unsigned int length=strlen(field);
if(this->length>0)
delete this->field;
this->field=new char[length];
this->length=length;
for(unsigned int i=0;i<length;i++)
this->field[i]=field[i];
return *this;
}
string& operator= (const string& str)
{
if(this!=&str)
*this=str.field;
return *this;
}
operator char* ()
{
return field;
}
friend std::ostream& operator<< (std::ostream& out, string& str);
friend std::istream& operator>> (std::istream& in, string& str);
public:
unsigned int length;
char* field;
};
std::ostream& operator<<(std::ostream& out, string& str)
{
out << str.field;
return out;
}
std::istream& operator>> (std::istream& in, string& str)
{
char temp[string::length_max];
in >> temp;
str=temp;
return in;
}
If I use the assignment operator, this doesn't cause a segmentation fault.
But it undirectly cause it.
I explain how:
int main(int argc,char** argv)
{
string str="hi";
string str2=str;
return 0;
}
Putting a breakpoint into the assignment operator overloading, I realized that the assigment operator doesn't cause segmentation fault.
The problem is after, when exiting from main.
If I remove the destructor I don't get this segmentation fault, but I would know why I get this problem.
Edit: I have understood where's the problem.
I followed your suggestions but it still goes to segmentation fault.
But now it doesn't crash anymore on the destructor method, but on the assignment operator overloading:
string& operator=(const char* field)
{
unsigned int length=0;
if(field!=NULL)
length=strlen(field);
else
field="";
if(this->length>0)
delete[] this->field;
this->field=new char[length+1];
this->length=length;
strcpy(this->field,field);
return *this;
}
The problem is when I delete this->field, the debugger stops there.
An example of segmentation fault:
string str("hi");
string str2=str;
This causes segmentation fault.I suppone it's because str2 is not initialized, and length has an undefined value.
If I instead do this:
string str("hi");
string str2;
str2=str;
There isn't any segmentation fault.Why?
I thought that calling :
string str2;
Was also calling the constructor, or is that the "=" operator has the precedence?
How to solve this?
PS: I also changed other things,like the copy constructor.
Full code is here:
http://pastebin.com/ubRgaVr8
Solved: I changed the copy constructor as suggested in the accepted reply:
string(const string& str)
{
length=str.length;
field=new char[str.length+1];
memcpy(field,str.field,length+1);
}
Your copy constructor doesn't initialise the object.
string(string& str)
{
string(str.field); // Does nothing
}
string(str.field)creates an unnamed stringand immediately throws it away.
It does not initialise this object using a different constructor.
Since your object now consists only of randomness, bad things will happen when you try to destroy it.
To make sure things are initialised, make a private member function
void initializeFromChars(const char* cString);
that does the work and use it in your constructors and assignment operator.
EDIT: Scrapped my previous answer, as it was incorrect.
The problem appears to be the copy constructor, you are passing the field from the source instance as though it is merely another null terminated char*, but it isn't.
You don't copy the null character at the end during the char* assignment invoked by the previous statement, you use an internal length field instead, and copy only that many bytes.
so your copy constructor should be:
string(string& str)
{
length = str.length;
field = new char[length];
memcpy(field, str.field, length);
}
or, if you want to preserve compatibility with null terminated functions, and you have ensured that the null is kept for all other assignments/constructors, etc:
string(string& str)
{
length = str.length;
field = new char[length + 1];
memcpy(field, str.field, length + 1);
}
In fact, the mixing null terminated, and specified length strings so much throughout your class appears to be confusing you.
I would create an internal, private, single disposal method, and an array of methods to set various source types, and have the constructors, assignment operators, and destructors use those instead.
That way you only have a single places where any given operation occurs, rather than juggling many minor variations on the same functionality. For example:
private:
void internalSet(const char *source) {
if (source == NULL) {
length = 0;
field = NULL;
}else{
length = strlen(source);
field = new char[length];
memcpy(field, source, length);
}
}
void internalSet(const string &source) {
length = source.length;
if (length > 0) {
field = new char[length];
memcpy(field, source.field, length);
}else{
field = NULL;
}
}
void internalDispose() {
delete[] field;
}
public:
string() : field(NULL), length(0) {}
string(const string& source) { internalSet(source); }
string(const char *source) { internalSet(source); }
~string() { internalDispose(); }
string& operator=(const char *source) {
internalDispose();
internalSet(source);
return *this;
}
string& operator=(const string &source) {
internalDispose();
internalSet(source);
return *this;
}
void clear() {
internalDispose();
length = 0;
}
Your destructor uses delete, when it should use delete[].
Once you allocate memory with
field = new char[length+1];
You should delete it with:
delete [] field;
And you're not checking whether your allocation was successful.
Another thing considered good practice is setting field to NULL after delete so it won't get deleted twice (if you start delivering classes) for example:
~string(){
delete [] field;
// field = NULL;
}
Note: according to Dietmar Kühl setting field=NULL isn't good practice (take a look at the comments) and choose your way, here's question specifically about this: Is it worth setting pointers to NULL in a destructor? .
Note 2: KerrekSB pointed out that delete [] field will do nothing if pointer is NULL and whole condition is unnecessary.
Than in string& operator=(const char* field) you probably want to allocate length + 1 and iterate to it too (to include terminating NULL).
And I don't like your string& operator= (const string& str), you have cached info on length of string and you're using strlen() and than manual copy char by char.
Your copy constructor also looks bad... You should "copy" manual allocation and copy byte by byte to it. Or rather build protected function like fromCString(const char *) and use it in both constructors and assign operators.
If those doesn't help ask in comment for more help.
I have the following class:
class StringHolder
{
public:
StringHolder(std::string& str)
{
m_str = &str;
}
private:
std::string* m_str;
};
And have the following string object (str), with a size of 1,024KB:
char c = 'a';
unsigned long long limit = 1024 * 1024;
std::stringstream stream;
for(int i = 0; i < limit; i++)
{
stream << c;
}
std::string str = stream.str();
Whenever I initialize the StringHolder class with a string, it doesn't make a copy of that string. That's because I used references & pointers, but I'm not sure if I used them properly :\
The question: did I use references & pointers properly?
The correct implementation should be something like
class StringHolder
{
public:
StringHolder(const std::string& str) //note const
: m_str(str){} //use initialization list
private:
std::string m_str; //no need to make it a pointer
};
Under the assumption that the lifetime of the string is known to outlive the object that will refer to it, and that the object will not need to modify the string, then you can take a constant reference to the string in the constructor and store that in:
class StringHolder {
std::string const & str;
public:
StringHolder( std::string const & s ) : str(s) {}
};
With this solution the contents of the string will not be copied, but any change to the original string will affect the contents seen from the reference. Also, this does not allow you to change the string referred to after construction. If you need to reseat the reference you will have to do with a pointer:
class StringHolder {
std::string const * str;
public:
StringHolder( std::string const & s ) : str(&s) {}
void reset( std::string const & s ) {
str = &s;
}
};
The fact that you need to store a pointer instead of a reference is an implementation detail, so you can (as I did) hide it from the user, or you could change the interface to take the string by pointer to make it more explicit (I prefer the former, but the later has the effect of self documentation: it is clearer that lifetimes have to be considered).
Also note that with the implementation as shown, a temporary can be used to initialize/set the string, causing undefined behavior: temporary dies, reference points to nowhere.