Look at the following code. What is wrong with it? The compiler gives the this error:
In copy constructor person::person(person&)':
No matching function for call toperson::copy(char*&, char*&)'
candidates are: void person::copy(char*&, const char*&) "
Here is the code:
class person
{
public:
person();
person(person &);
private:
void copy(char*&,const char*&);
char* name, *fathername,* address;
};
void person::copy( char*& n, const char*& p)
{
int result;
result=strcmp(n,p);
if(result!=0)
{
n=new char[strlen(p)+1];
strcpy(n,p);
n[strlen(p)]='\0';
}
}
person::person(person &object)
{
copy(name,object.name);
copy(fathername,object.fathername);
copy(address, object.address);
}
From the answers to this Question what I understood up until now is given by:
the compiler does not allow to convert a reference to a constant reference because references are already constant. They can't point to a different memory location like pointer. Am I right?
Wouldn't this be nicer?
class person
{
private:
std::string name;
std::string fathername
std::string address;
};
// constructor and copy constructor autogenerated!
It's more "C++" this way ;).
Unless you are planning on changing the pointers you should not pass the references to the pointers:
Change:
void person::copy( char*& n, const char*& p)
to
void person::copy( char* n, const char* p)
This is because p is a reference to a particular type.
The object you passed is not the exact type and becuase it is a reference their is no way to convert it.
The change I suggested above allows for a "pointer to const char" (p) thus allowing read only access to elements via 'p'. Now a "pointer to char" allows read/write access to the data so converting this to "pointer to const char" is allowed because we are just limiting the allowed behavior.
There are a whole set of other problems with the code you posted.
Do you want us to list them?
I don't do NOW. I do on my schedule.
Problems:
1: You leak on each call to copy:
if(result!=0)
{
n=new char[strlen(p)+1]; // What happned to the old n?
2: The default assignment operator is used.
person a;
person b;
a = b; // a.name == b.name etc all point at the same memory location.
// Though because you do not delete anything in the destructor
// it is technically not an issue yet.
3: You done delete the allocated members in the destructor.
{
person a;
} // A destructor called. You leak all the member here.
4: strcpy() already copies the terminating '\0' character.
5: if the call to new throws an exception. You will leak memory.
copy(name,object.name);
copy(fathername,object.fathername); // If new throws in here.
// Then the this.name will be leaked.
Doing this correctly using C-String is so hard that even a C++ expert would have problems doing this correctly. Thats why C++ experts would use std::string rather than a C-String. If you must use C-Strings then you should wrap your C-String in another class to protect it from probelms with exceptions.
Change
person::person(person &object)
to
person::person(const person &object)
for starters...
The compiler is telling you the problem - change your signature to accept 2 char* pointers (rather than 1 const char*) and it should compile.
The issue is really due ot the use of the reference - if you had created a copy method that simply took 2 char* pointers (not references) then the compiler will automatically recognise the conversion from char* to const char* and use the method. As you only have a method that accepts a reference to a different type it cannot do that automatically.
I'm feeling generous, so here is a corrected version of your code:
class person
{
public:
person();
person(const person &);
~person();
private:
void copy(char*&, // Do you understand purpose of '&' here?
const char*);
char* name;
char* fathername;
char* address;
};
person::person()
: name(NULL),
fathername(NULL),
address(NULL)
{
}
person::~person()
{
delete[] name;
delete[] fathername;
delete[] address;
}
void person::copy( char*& n, // The '&' is required because the contents of `n` are changed.
const char* p)
{
delete[] n;
n = NULL; // Here is one place where contents of `n` are changed.
if (p)
{
n = new char [strlen(p) + sizeof('\0')]; // Another content changing location.
strcpy(n, p);
n[strlen(p)]='\0';
}
}
person::person(const person& object)
{
copy(name,object.name);
copy(fathername,object.fathername);
copy(address, object.address);
}
Can you identify the flaws or safety items still lurking?
As others are saying, you shouldn't pass the char pointer by reference if you are not going to modify it.
The problem is that the reference is non-const and therefore doesn't bind to temporaries. Therefore the passed variable's type must match exactly. Near matches that would involve an implicit cast are not acceptable, because the result of an implicit cast is a temporary.
Const references, on the other hand, can be bound to temporaries.
void non_constant(int&);
void constant(const int&);
int main()
{
int i = 0;
unsigned u = 0;
non_constant(i);
//non_constant(u); //ERROR: not an int
//non_constant(10); //ERROR: literals are temporaries
constant(i);
constant(u); //OK, unsigned implicitly cast to int
constant(10); //OK, literals bind to const references
}
So, if you wanted badly to keep the reference in the argument:
void person::copy( char*& n, const char* const& p)
This is VERY (!) poor design. This code is buggy and VERY (!) hard to understand and maintain.
This question is continuation for this question: C++ classes , Object oriented programming.
Now you struggling with symptoms, not with real problem. And real problem is to think in C++ terms not in C (if you want to became C++ object-oriented programmer).
Valid C++ code (C++, not C with classes) here:
#include <string>
class person
{
public:
person();
private:
std::string name, fathername, address;
};
Thats all. All other things (including copy contstructor) C++ compiler generates for you (as well effective as you own manual implementation)! This much simpler, much clearer, easier to maintain and understand, and first of all: bug free;). And this is true C++ code.
Others have already correctly answered your question, but it seems you didn't understand it so far, so I will try to make it as clear as possible for you.
void person::copy( char*& n, const char*& p)
This function expects as the second argument a non-const reference to a const pointer (and not a const reference to a pointer as you might think!).
When you try to call this function passing as the second argument a pointer (not a const pointer) the compiler is unable to create a reference for it, simply because it expects to bind a reference to a const pointer and it is not allowed to implicitly cast the pointer to a const pointer, since non-const references may not bind to rvalues (temporary values).
If you want the function to expect a const reference to a const pointer, you have to change its signature as shown below:
void person::copy( char*& n, const char* const& p)
Here it is important to understant that the compiler implicitly casts the provided pointer to a const pointer before binding the reference, which is allowed in this case, since a const reference may bind both to rvalues and lvalues.
Similarly, if you want the function to expect a const reference to a pointer, which was probably your original intention, then the signature should be as shown bellow:
void person::copy( char*& n, char* const& p)
Here the compiler doesn't have to implicitly cast anything, since the provided argument already matches the type the reference expects to bind.
I hope I made it clear and detailed for you and that you correctly understood what caused the problem, which is indeed important, but nonetheless, I would strongly advice you not to write your code like this, but instead to follow the suggestions given by the others.
Others pointed that you should replace reference with pointer.
Here are a few other but related comments:
If you define copy constructor, define assignment operator too. They should go along together, in most cases.
It's a good practice to declare single argument constructor as explicit.
Naming objects as object is a bad convention and may lead to confusions. It's abvious every instance of type person is an object. Use more meaningful names, like person(const person& other); or person(const person& rhs); // after right-hand-side
Use std::string. If you are programming in C++, there is no
rational reason to not to use std::string and juggle C-strings instead.
Finally, take care of exception safety, follow best practices like copying oprations implemented in terms of non-throwing swap operation. See article Exception-Safe Class Design, Part 1: Copy Assignment by Herb Sutter
Related
I get stuck when trying to understand following code.
class V8_EXPORT Utf8Value {
public:
explicit Utf8Value(Local<v8::Value> obj);
~Utf8Value();
char* operator*() { return str_; }
const char* operator*() const { return str_; }
int length() const { return length_; }
private:
char* str_;
int length_;
Utf8Value(const Utf8Value&);
void operator=(const Utf8Value&);
};
Line: "~Utf8Value();"
When I checked the cpp file, it contains only one line:
String::Utf8Value::~Utf8Value() {
i::DeleteArray(str_);
}
Does it mean that the function is to delete the char* str_? Is there any reason why got a ~ before the function name? Can I rename it to other names instead of ~Utf8Value?
Line: const char* operator*() const { return str_; }
What does it do? Why there is a * after function name?
My understanding of const is that the fucntion/variable will never change, but what does the second const after brackets mean?
Line: Utf8Value(const Utf8Value&);
Is it another constructor like the first line explicit Utf8Value(Local<v8::Value> obj); ?
Line: void operator=(const Utf8Value&);
I have no idea what this line is trying to do.
Can anyone help me with this? Any help would be much appreciated!
Thank you!!
It seem you do not know the C++ syntax well before you try to read some bigger project source code.
To your question:
A function start with '~' in class declaration (scope) is the Destroy function of a class object which call automatically when the object is die or deleted. In this case, An object of Utf8Value (let us call it object at next) have been hold a str_ pointing to somewhere that need to free when the host being destroying. Get to give, give to get. Finally, you can not rename it.
This line declares a behavior when treat this object as a char* string. What does it did this here call operator override in C++ and most operator can be designed as what you want, like arithmetic, compare, shift, etc. That is a very peculiar characteristics of C++. For the 'const' function, it means this function will not change something in this object.
Yes. But since it is declared in the private scope, it can NOT be called out of the object or another constructor. Generally speaking, it is designed to forbidding construct an object in a way that designer does not want.
It works like question 3 while trying to stop constructing an object from value assignment.
Actually,i'm having many doubts regarding string operations.Firstly,
I'm confused regarding the use of copy constructor for string concatenation.Is there a need of copy constructor,or just by using parameterized constructor,it can be done.I mean
class string{
char*p;
int size;
public: string(char *a){
size= strlen(a);
p=new char[size];
strcpy(p,a);
}
The above code,initailizes the object dynamically.
how does pointer work if passed as argument in above code,what if i pass char array a[].
Also,the strcpy copies the string.now if i use operator overloading i.e
string operator+(string c) // i'm defining the function in class definition.
{
string t;
t.size=size + c.size;
t.p=new char[t.size];
strcat(t.p,c.p);
return t;
}
Do i need a copy constructor?and why?
Also can anyone explain me what actually happens when working with pointers to char as in this case.
Secondly,in main() if i declare the objects.Will it be wrong to write
string ob1("Hello world");
or should i proceed as
char *str;
str="Hello world";
Plz do point out the errors in my code snippet's too,if any.when i'm running the program,it stops in between and it promts program has stopped working.
Why so?
Do i need a copy constructor?
In general, a class that manages resources does, and you should provide one (along with a constructor and copy-assignment operator) to make the class useful.
However, you shouldn't just for this operator; but your implementation does...
and why?
Because your operator takes its left-hand argument by value, which requires it to be copied. Take it by reference instead:
string operator+(string const & c) const
(It's a good idea for both operands to be const, both to prevent accidental modification, and to allow the operator to be applied to constant values).
However, if you want to fix the memory leak (by deleting the array in the destructor) then you should either provide or delete the copy constructor and copy-assignment operator to avoid double deletion. See this question for the gory details of making a type copyable.
string ob1("Hello world");
This might fail (with modern compilers) since your constructor takes a non-const char*, while the string literal decays to const char*. You should change the constructor argument to const char* to match (and, in general, always make pointers and references const when you don't need to use them for modification).
i could not find threads giving a clear answer on this -
i have a constructor, for example:
FanBookPost::FanBookPost(Fan* owner, std::string content);
Fan is another class in my code, but content is the problematic one:
since std::string is not a pointer, i would expect that calling the constructor with (fan, nullptr) would not be possible. however, it compiles! ... and crashes at runtime with EXC_BAD_ACCESS.
is this avoidable?
The problem here is that the crash will occure when the constructor of std::string is called (as a nullptr interpreted as const char* is accessed there). There is nothing here you can do against this but to tell other peoples not to do shit. Its not a problem of your constructor and thus not your responsibility (besides that you cant prevent it).
What you're observing is that you can implicitly create a std::string from a character pointer (nullptr in this case) which is then passed to the function. However creating a string from a null pointer is not allowed. There is nothing wrong with your method signature, just the client use that violates the std::string constructor's contract.
How about using a proxy / wrapper typ, if you really want to be safe:
template<typename T>
struct e_t
{
public:
inline e_t ( e_t const & other )
: m_value( other.m_value )
{}
inline T & value( void ) { return m_value; }
inline operator T&() { return m_value; }
inline e_t( const T& c ) : m_value( c ) {}
private:
T m_value;
};
void FanBookPost(int* owner, e_t<std::string> content) {
}
int main()
{
int n = 0;
//FanBookPost(&n, 0); // compiler error
//FanBookPost(&n, nullptr); // compiler error
//FanBookPost(&n, ""); // unfortunately compiler error too
FanBookPost(&n, std::string(""));
}
The problem is that std::string has a non-explicit ctor that takes a char * as its sole (required) parameter. This gives an implicit conversion from nullptr to std::string, but gives undefined behavior, because that ctor specifically requires a non-null pointer.
There are a few ways to prevent this. Probably the most effective would be to take a (non-const) reference to a std::string, which will require passing a (non-temporary) string as the parameter.
FanBookPost::FanBookPost(Fan* owner, std::string &content);
This does have to unfortunate side effect of giving the function the ability to modify the string that's passed. It also means that (with a conforming compiler1) you won't be able to pass nullptr or a string literal to the function--you'll have to pass an actual instance of std::string.
If you want to be able to pass a string literal, you can then add an overload that takes a char const * parameter, and possibly one that takes a nullptr_t parameter as well. The former would check for a non-null pointer before creating a string and calling the function that takes a reference to a string, and the latter would do something like log the error and unconditionally kill the program (or, just possibly, log the error and throw an exception).
That's annoying and inconvenient, but may be superior to the current situation.
Unfortunately, the last time I noticed MS VC++ did not conform in this respect. It allows passing a temporary object by non-const reference. Normally that's fairly harmless (it just lets you modify the temporary, but that normally has no visible side effects). In this case it's much more troublesome though, since you're depending on it specifically to prevent passing a temporary object.
This question already has answers here:
Are the days of passing const std::string & as a parameter over?
(13 answers)
Closed 9 years ago.
There is a set of good rules to determine whether pass by value or const reference
If the function intends to change the argument as a side effect, take
it by non-const reference.
If the function doesn't modify its argument and the argument is of
primitive type, take it by value.
Otherwise take it by const reference, except in the following
cases: If the function would then need to make a copy of the const
reference anyway, take it by value.
For constructor as following, how to determine it?
class A
{
public:
A(string str) : mStr(str) {} // here which is better,
// pass by value or const reference?
void setString(string str) { mStr = str; } // how about here?
private:
string mStr;
};
In this particular case, and assuming C++11 and move construction/assignment for strings, you should take the argument by value and move it to the member for the constructor.
A::A(string str) : mStr(std::move(str)) {}
The case of the setter is a bit trickier and I am not sure whether you really want/need to optimize every bit of it... If you want to optimize the most you could provide two overloads, one taking an rvalue reference and another taking a const lvalue reference. At any rate, the const lvalue reference is probably a good enough approach:
void A::setString(string const& str) { mStr = str; }
Why the difference?
In the case of the constructor, the member is not yet built, so it is going to need to allocate memory. You can move that memory allocation (and actual copying of the data, but that is the leaser cost) to the interface, so that if the caller has a temporary it can be forwarded without an additional memory allocation.
In the case of assignment the things are a bit more complicated. If the current size of the string is large enough to hold the new value, then no allocation is required, but if the string is not large enough, then it will need to reallocate. If the allocation is moved to the interface (by-value argument), it will be executed always even when it is unnecessary. If the allocation is done inside the function (const reference argument) then for a small set of cases (those where the argument is a temporary that is larger then the current buffer) an allocation that could otherwise have been avoided would be done.
The article you site is not a good reference for software
engineering. (It is also likely out of date, given that it
talks about move semantics and is dated from 2003.)
The general rule is simple: pass class types by const reference,
and other types by value. There are explicit exceptions: in
keeping with the conventions of the standard library, it is also
usual to pass iterators and functional objects by value.
Anything else is optimization, and shouldn't be undertaken until
the profiler says you have to.
In this case it is better to pass argument by const reference. Reason: string is a class type, you don't modify it and it can be arbitrary big.
It is always better to use the member initialization list to initialize your values as it provides with the following advantages:
1) The assignment version, creates a default constructor to initialize mStr and then assigned a new value on top of the default-constructed one. Using the MIL avoids this wasted construction because the arguments in the list are used as constructor arguments.
2) It's the only place to initialize constant variables unless these are just intergers which you can use enums in the class. enum T{v=2};
3) It's the place to initialize references.
This is what I would suggest:
#include <iostream>
#include <string>
class A
{
private:
std::string mStr;
public:
A(std::string str):mStr(str){}
//if you are using an older version of C++11, then use
//std::string &str instead
inline const void setString(std::string str)
{
mStr = str;
}
const std::string getString() const
{
return mStr;
}
};
int main()
{
A a("this is a 1st test.");
a.setString("this is a 2nd test.");
std::cout<<a.getString()<<std::endl;
}
Have a look at this:
http://www.cplusplus.com/forum/articles/17820/
As a common rule, it is very often considered a bad practice to use const_cast<>() in C++ code as it reveals (most of the time) a flaw in the design.
While I totally agree with this, I however wonder what are the cases were using const_cast<>() is ok and the only solution.
Could you guys please give me some examples you know/you encountered ?
Thank you very much.
it is pretty much designed to be only used with legacy APIs that are not const correct i.e. with a function you can't change that has non const interface but doesn't actually mutate anything on the interface
Like others have said, its primary purpose is to remove const from objects in order to pass to non-const correct functions you know won't modify the argument.
There is a trick (by Meyers?) to avoid code duplication, and it goes like this:
struct foo
{
const return_type& get(void) const
{
// fancy pants code that you definitely
// don't want to repeat
return theValue; // and got it
}
return_type& get(void)
{
// well-defined: Add const to *this,
// call the const version, then
// const-cast to remove const (because
// *this is non-const, this is ok)
return const_cast<return_type&>(static_cast<const foo&>(*this).get());
}
};
const_cast is also used to remove volatile modifiers, as put into practice in this (controversed) article:
http://www.drdobbs.com/184403766
I agree with your statement that its normal use is because you need to hide a 'design flaw'.
IME one of the typical usage scenarios is when you try to interface C++ to existing C code. A lot of existing C code takes C strings as char * even when the string is not modified whereas they're usually represented as something that converts to a const char * in C++. That's an impedance mismatch between the two languages that you would normally solve by using a const_cast. Of course you'd better be very sure that the code you're interfacing with doesn't get any cute ideas about modifying the data that's being passed in.
I would say that it's a code smells in newly written code, but for interfacing with older C and C++ code, it's an necessary evil. That said, I would be extremely wary of code that requires const_cast for any non-POD objects as that is normally a problem that should be solved at the design level and not the code level.
One legitimate use (in my opinion) is with std::set iterators. They are always const, in order to prevent changing the key used in the set. Changing the key would break the internal structure of the set and cause undefined behavior.
However, as long as the key doesn't change it's safe to change other data in the object.
Let's say you have an std::set like this:
std::set<MyObject> some_set;
And a class like this:
class MyObject {
public:
MyObject(const std::string &key)
: key_(key) {}
bool operator<(const MyObject &other) const {
return key_ < other.key_;
}
private:
// ...
// <some other data>
// ...
const std::string key_;
};
In the above example, the key is already const, so even if you modify the object, you cannot break the internal structure of the set.
Normally you can only get a const reference out of a set iterator:
const MyObject &object = *some_set_iterator;
But since the key is const, it's safe to const_cast the dereferenced iterator:
MyObject &object = const_cast<MyObject &>(*some_set_iterator);
One very legitimate use of this is when you have both a const and non const api (for const and non const objects respectively) as in
class Bar {
const SomeType& foo() const;
SomeType& foo();
}
Then since we don't want to duplicate the code in both functions we often use
class Bar {
SomeType& foo() {
//Actual implementation
}
const SomeType& foo() const {
return const_cast<Bar*>(this)->foo();
}
};
This is of course assuming that foo does not do something that violates the const semantics.
Yes of course, when your calling code that you can't modify and isn't const correct. It should be noted that you should only use it with calls to functions that you know for certain won't modify your data!
There is an example of const_cast usage in c++ primer(5th edition) book.
Below function returns reference to const string
// return a reference to the shorter of two strings
const string &shorterString(const string &s1, const string
&s2)
{
return s1.size() <= s2.size() ? s1 : s2;
}
The book then mentions the case when we want a non const reference.
We can call the function on a pair of nonconst string arguments, but
we’ll get a reference to a const string as the result. We might want
to have a version of shorterString that, when given nonconst
arguments, would yield a plain reference. We can write this version of
our function using a const_cast:
string &shorterString(string &s1, string &s2)
{
auto &r = shorterString(const_cast<const string&>(s1),
const_cast<const string&>(s2));
return const_cast<string&>(r);
}
This version calls the const version of shorterString by casting its
arguments to references to const. That function returns a reference to
a const string, which we know is bound to one of our original,
nonconst arguments. Therefore, we know it is safe to cast that string
back to a plain string& in the return.
According to the book, it should be used if we know it is safe to cast.