For legacy reasons, there's a lot of usage of const char* in the code I'm working on. I am trying to limit that, and stumbled on something I'd like to know. I have something like:
class AClass {
public:
const char* getValue() { return _value.c_str(); }
private:
std::string _value;
}
But this class now may be returned by copy, eg. by function:
AClass getAClass();
We also might wanna pass that to something like this:
void functionFromOtherLibrary(const char* value);
Now thinking about that, this might cause an error:
functionFromOtherLibrary(getAClass().getValue());
since the intermediate is eligible to be destroyed at that point. Even if the above goes OK, because it's one statement, this probably won't:
const char* str = getAClass().getValue();
functionFromOtherLibrary(str);
So I was thinking of writing something like:
class AClass {
public:
const char* getValue() { return _value.c_str(); }
const char* getValue() && = delete;
}
to forbid calls for that method on rvalues. Just trying that gave me:
error C2560: cannot overload a member function with ref-qualifier with a member function without ref-qualifier
I'm not sure if this:
is valid construct and
is ever necessary. I've seen a lot of code that returns const char*s and it always seems to rely on the fact that the object returning the value will still exist and hold the source std::string.
I would really appreciate a more detailed explanation what happens when code uses std::strings to hold strings but only communicates with C strings.
And if you want to suggest removing C strings - that's what I'm trying to do right now. I still want an answer though.
You can't overload a function with a ref-qualifier with a function without a ref-qualifier. The MSVC error text is nice and clear on this point.
But you can just add the ref-qualifier to the other one:
class AClass {
public:
const char* getValue() & { return _value.c_str(); }
const char* getValue() && = delete;
};
Whether this is the right design or not is a separate question - but if you decide that it is, this is how you would do it.
Related
This is a question to understand the correct way to implement a get function in the below scenario.
I got the below class:
class A
{
string m_sName;
public:
A(): m_sName ("this") {}
const string& getName() const
{
return m_sName;
}
};
The problem with the above implementation of the get function is, it allows the client to modify the data member. That's:
int main ()
{
A a;
const string& data_mem = a.getName();
string& s = const_cast<string&> (data_mem);
s += " Pointer";
cout << a.getName().c_str () << endl;
return 0;
}
The output would be: this Pointer
I know we can use reference parameter for get function or simply return string. But both will create new object.
Is there a better way to do this? Or prohibit const_cast (on a user defined class)?
C++ gives you the ability to shoot yourself in the foot.
Programmers should use const_cast with extreme caution: being aware that the behaviour on using it to cast away the const on an object that was initially declared as const is undefined.
Code analysis tools could help you.
You could avoid the problem completely by simply returning by value
string getName() const
Add another version of getName() that isn't marked as a const method and returns a non-const string&:
string& getName() { return m_sName; }
That will return a reference to the string in the instance of A, and won't create a copy. It will however amend the string in the class.
I should point out this is the wrong way to do things in OO terms, both in terms of encapsulation and data hiding. Your class's abstraction for how the name is stored is leaking to the outside world. The correct approach would be to add an UpdateName or AppendToName method.
I've got a const method in my class, which cannot be changed to non-const. In this method, I need to call a non-const method but the compiler doesn't let me do that.
Is there any way around it? Here is a simplified sample of my code:
int SomeClass::someMethod() const {
QColor saveColor = color();
setColor(QColor(255,255,255)); // Calling non-const method
// ....
setColor(saveColor); // restore color
return 1;
}
You could use const_cast on this pointer,
int SomeClass::someMethod() const {
const_cast<SomeClass*>( this )->setColor(...);// Calling non-const method
//whatever
}
but if you do that for an object that was originally declared const you run into undefined behavior.
So this:
SomeClass object;
object.someMethod();
is okay, but this:
const SomeClass object;
object.someMethod();
yields undefined behavior.
The real solution is that your const function should not be const in the first place.
One of the challenges of doing const-correctness is you can't do it halfway. It's either all or nothing. If you try to do it halfway, you end up in a tough spot like you are here. You end up with a nice const-correct class being used by some crazy old, typically legacy (or written by an old curmudgeon) code that isn't const-correct and it just doesn't work. You're left wondering if const-correctness is worth all the trouble.
I need to call a non-const method [from a const method]
You can't -- not directly. Nor should you. However, there is an alternative...
Obviously you can't call a non-const method from a const method. Otherwise, const would have no meaning when applied to member functions.
A const member function can change member variables marked mutable, but you've indicated that this is not possible in your case.
You could attempt to cast away constness by doing something like SomeClass* me = const_cast<SomeClass*>(this); but A) This will typically result in UB, or 2) It violates the whole idea of const-correctness.
One thing you could do, if what you're really trying to accomplish would support this, is to create a non-const proxy object, and do nonconst-y stuff with that. To wit:
#include <iostream>
#include <string>
using namespace std;
class Gizmo
{
public:
Gizmo() : n_(42) {};
void Foo() const;
void Bar() { cout << "Bar() : " << n_ << "\n"; }
void SetN(int n) { n_ = n; };
int GetN() const { return n_; }
private:
int n_;
};
void Gizmo::Foo() const
{
// we want to do non-const'y things, so create a proxy...
Gizmo proxy(*this);
int save_n = proxy.GetN();
proxy.SetN(save_n + 1);
proxy.Bar();
proxy.SetN(save_n);
}
int main()
{
Gizmo gizmo;
gizmo.Foo();
}
If you require to change some internal state inside a const-method you can also declare the affected state mutable:
class Foo {
public:
void doStuff() const { bar = 5; }
private:
mutable int bar;
};
This is intended for cases where you have stuff like mutexes as members of your class. Acquiring and releasing a mutex does not affect client-visible state, but is technically forbidden in a const-method. The solution is to mark the mutex mutable. Your case looks similar, although I think your class requires some refactoring for this solution to be applicable.
Also, you might want to read this answer to see how you can make this temporary state-change exception-safe using RAII.
How to call a non-const method from a const method?
You should not. You might run into undefined behaviour if you cast away the const-ness of this, using const_cast. The usage ofconst_cast will shut the compiler's mouth up, but that isn't a solution. If you need to do, then it means the const function should not be const in the first place. Make it non-const.
Or, you should do something else, which would not require you to call non-const function from const function. Like, don't call setColor function? Like, split the const function into more than one functions (if you can do that)? Or something else?
In your particular case, if setColor only sets some member variable, say m_color, then you can declare it mutable:
mutable QColor m_color;
and then set it in your const function, without calling setColor function, and without doing const_cast.
Ok, I know that operator. is not overloadable but I need something like that.
I have a class MyClass that indirectly embeds (has a) a std::string and need to behave exactly like a std::string but unfortunately cannot extend std::string.
Any idea how to achieve that ?
Edit: I want that the lines below to compile fine
MyClass strHello1("Hello word");
std::string strValue = strHello1;
const char* charValue = strHello1.c_str();
As per your later edit, that:
MyClass strHello1("Hello word");
std::string strValue = strHello1;
const charValue = strHello1.c_str();
should compile fine, the only solution is to write a wrapper over std::string:
class MyClass
{
private:
std::string _str;
public:
MyClass(const char*);
//... all other constructors of string
operator std::string& ();
//... all other operators of string
const char* c_str();
//... all other methods of string
friend std::string& operator + ( std::string str, Foo f);
};
//+ operator, you can add 2 strings
std::string& operator + ( std::string str, Foo f);
This however is tedious work and must be tested thoroughly. Best of luck!
You can overload the conversion operator to implicitly convert it to a std::string:
class MyClass
{
std::string m_string;
public:
operator std::string& ()
{
return m_string;
}
};
If you're not interested in polymorphic deletion of a string*, you can derived from std::string, just getting the behavior of your class behaving "as-a" std::string. No more, no less.
The "you cannot derived from classes that don't have a virtual destructor" litany (if that's the reason you say you cannot extend it) it like the "dont use goto", "dont'use do-while" "don't multiple return" "don't use this or that feature".
All good recommendation from and for people that don't know what they are doing.
std::string doesn't have a virtual destructor so don't assign new yourcalss to a std::string*. That's it.
Just make your class not having a virtual destructor itself and leave in peace.
Embedding a string and rewriting all its interface just to avoid inheritance is simply stupid.
Like it is stupid writing dozens of nested if to avoid a multiple return, just as its stupid introduce dozens of state flags to avoid a goto or a break.
There are cases where the commonly considered weird things must be used. That's why those things exist.
You can extend an interface without publically deriving from it. This prevents the case of problematic polymorphic destruction (aka no virtual destructor):
#include <iostream>
#include <string>
using namespace std;
class MyClass
: private std::string
{
public:
MyClass(const char* in)
: std::string(in)
{}
// expose any parts of the interface you need
// as publically accessible
using std::string::c_str;
using std::string::operator+=;
};
int main()
{
MyClass c("Hello World");
cout << c.c_str() << "\n";
c += "!";
cout << c.c_str() << "\n";
// Using private inheritance prevents casting, so
// it's not possible (easily, that is) to get a
// base class pointer
// MyClass* c2 = new MyClass("Doesn't work");
// this next line will give a compile error
// std::string* pstr = static_cast<MyClass*>(c2);
// delete c2;
}
Trying to sum-up all the discussions, it looks like you will never find a suitable dolution because ... your requirements are in cotraddiction.
You want you class to behave as ats::string
std::string behave as a value but
a value does not "change" when accessed but (think to c = a+b: do you expect a and b to change their value ??) ...
when accessing your "value" you want to change it.
If what I summed up collecting all the peaces (suggestion: edit your question otherwise all the answerer will risk to be lost) is correct you are in trouble with 3 & 4 (note the 3. derives from the concept of "assignment", and you can do noting to change it, while 4. comes from you directly)
Now, I can try to reverse-engineer your psychology (because you didn't provide good information about what your class represent and why you cannot "extend" a string) I can find
two possibility neither of which will fit all the above requirements.
Store a string into your class and make your class to behave as a std::string. There are threee ways to come to this point:
a. embed a string and make your class to decay to it:
essentially your class must contain
.
operator std::string&() { return my_string; } //will allow l-value assignments
operator const std::string&() const { return my_string; } //will allow r-value usage
const char* c_str() const { return my_string.c_str(); }
b. derive from std::string. In fact that's like having an anonymous my_string in it, which "decay" operations implicit. Not that different as above.
c. embed or privately derive, and rewrite the std::string interface delegating the std::string functions. It's just a long typing to get exactly the b. result. so what the f..k? (this last question is dedicated to all the ones that believe a. or b. will break encapsulation. c. will break it as well, it will only take longer!)
Don't store a string, but just get it as a result from a calculation (the "lookup" you talk about, not clarifying what it is).
In this last case, what you need is a class that decay automatically into std::string as a value.
So you need, in your class
operator std::string() const { return your_lookup_here; }
note that const is necessary, but there is no need to modify your class inner state, since the resulting string is not stored.
But this last solution has a problem with const char*: since the string is temporary, until you don't assign it, its buffer is temporary as well (will be destroyed) so decaying into const char* to assign the pointer is clueless (the pointer will point to a dead buffer).
You can have a
const char* c_str() const { return std::string(*this).c_str(); } //will call the previous one
but you can use this only into expressions or a pass-through parameter in function calls (since the temporary will exist until the evaluating expression is fully evaluated), not in an assignment towards an l-value (like const char* p; p = myclassinstace.c_str(); )
In all of the above cases (all 1.) you also need:
myclass() {}
myclass(const std::string& s) :my_string(s) { ... }
myclass(const char* s) :my_string(s) { ... }
or - in C++11, just
template<class ...Args>
myclass(Args&&... args) :my_string(std::forward<Args...>(args...)) {}
In case 2., instead of initialize the not existent my_sting, you should use the arguments to set what you will look up (we don't know what it is, since you did not tell us)
Hope in all these option you can find something useful.
You can add an operator const reference to string, as follows:
class C
{
public:
// Implicit conversion to const reference to string (not advised)
operator const std::string &() const
{
return s_;
}
// Explicit conversion to a const reference to string (much better)
const std::string &AsString() const
{
return s_;
}
private:
std::string s_;
};
As you can see from the comments, it would be much better to add an explicit conversion function if you really need this behavior. You can read about why this is bad in the Programming in C++ Rules and Recommendations article.
I have an a class which is singleton as defined follows
class myData {
private:
myData (void); // singleton class.
// Copy and assignment is prohibted.
myData (const myData &);
myData & operator=(const myData &);
static myData* s_pInstance;
public:
~myData (void);
static const myData & Instance();
static void Terminate();
void myFunc() { cout << "my function..." ;}
};
// In cpp file.
myData* myData::s_pInstance(NULL);
myData::myData(){}
myData::~myData()
{
s_pInstance = NULL;
}
const myData& myData::Instance()
{
if (s_pInstance == NULL)
{
s_pInstance = new myData();
}
return *(s_pInstance); // want to avoid pointer as user may deallocate it, so i used const referense
}
void main() {
(myData::Instance()).myFunc();
}
I am getting following error
error C2662: 'myData::myFunc' : cannot convert 'this' pointer from 'const myData' to 'myData&'
how to avoid above problem and call a function from Instance function which is returning const reference?
Thanks!
You'd want to declare func() as a constant member function, so the compiler knows it won't violate the const'd return value from the instance() function.
You could instead also make the instance() function return a 'regular' reference as apposed to a const one.
So either turn:
void myFunc() into void myFunc() const
Or turn:
const myData& myData::Instance() into myData& myData::Instance()
If you are calling a function on a const reference, the function you call must also be const, in your case void myFunc() const.
Otherwise you might return a non-const reference, if that works better.
The error says that myData::Instance() is a const instance of the class, and it can't call myFunc() on that, because myFunc() might change the instance, and you can't change a const instance.
Of course, you know that myFunc() can't really change the instance, but you must advertise this fact, as follows:
void myFunc() const { cout << "my function..." ;}
Avoiding the whole discussion of whether Singleton is a good to have pattern or the source of all evil, if you are actually implementing a singleton, chances are that const correctness will not work there as you expect it, so you should be aware of some pitfalls.
First your error: your Instance() static member returns a const reference, and that means that you can only perform operations that do not modify the object, i.e. call member functions marked as const, or use public members if present in a way that do not modify their values. My suggested solution is modify Instance() to return a non-const reference, rather than making func() const as others suggest.
Now for a longer explanation to the problem of const-correctness in general when applied to your particular Singleton problem. The basic problem is that when you implement a type, you divide those members that modify the object from those that don't, and you mark the latter as const member functions so that the compiler knows of your promise (allows you to call that method on a constant object) and helps you not break it (complains if you try to modify the state in the definition of the method). A method that is marked as const can be applied to both a constant and non constant object, but a method that is not marked const can only be applied to an object that is not const.
Back to the original piece of code, if you implement a singleton and the only way of accessing the object is by an Instance() method that returns a const reference, you are basically limiting all user code to use only const methods implemented in your interface. That means that effectively either all methods are non-mutating, or they are useless (const_cast should never be used). That in turn means that if you have any non-const operation you want to provide an Instance() method that returns a non-const reference.
You could consider implementing two variants of Instance(), but that will not be really helpful. Overload resolution will not help in user code to determine which version to use, so you will end up having to different methods: Instance(), ConstInstance() (choose your names), which means that it is up to user code to determine which one to use. The small advantage is that in their code, the choice of accessor will help documenting their intended usage, and maybe even catch some errors, but more often than not they will just call the non-const version because it works.
This question already has answers here:
Meaning of 'const' last in a function declaration of a class?
(12 answers)
Closed 5 years ago.
I've seen a lot of uses of the const keyword put after functions in classes, so i wanted to know what was it about. I read up smth at here: http://duramecho.com/ComputerInformation/WhyHowCppConst.html .
It says that const is used because the function "can attempt to alter any member variables in the object" . If this is true, then should it be used everywhere, because i don't want ANY of the member variables to be altered or changed in any way.
class Class2
{ void Method1() const;
int MemberVariable1;}
So, what is the real definition and use of const ?
A const method can be called on a const object:
class CL2
{
public:
void const_method() const;
void method();
private:
int x;
};
const CL2 co;
CL2 o;
co.const_method(); // legal
co.method(); // illegal, can't call regular method on const object
o.const_method(); // legal, can call const method on a regulard object
o.method(); // legal
Furthermore, it also tells the compiler that the const method should not be changing the state of the object and will catch those problems:
void CL2::const_method() const
{
x = 3; // illegal, can't modify a member in a const object
}
There is an exception to the above rule by using the mutable modifier, but you should first get good at const correctness before you venture into that territory.
Others have answered the technical side of your question about const member functions, but there is a bigger picture here -- and that is the idea of const correctness.
Long story short, const correctness is about clarifying and enforcing the semantics of your code. Take a simple example. Look at this function declaration:
bool DoTheThing(char* message);
Suppose someone else wrote this function and you need to call it. Do you know what DoTheThing() does to your char buffer? Maybe it just logs the message to a file, or maybe it changes the string. You can't tell what the semantics of the call are by just looking at the function declaration. If the function doesn't modify the string, then the declaration is const incorrect.
There's practical value to making your functions const correct, too. Namely, depending on the context of the call, you might not be able to call const-incorrect functions without some trickery. For example, assume that you know that DoTheThing() doesn't modify the contents of the string passed to it, and you have this code:
void MyFunction()
{
std::string msg = "Hello, const correctness";
DoTheThing(msg.c_str());
}
The above code won't compile because msg.c_str() returns a const char*. In order to get this code to compile, you would have to do something like this:
void MyFunction()
{
std::string msg = "Hello, const correctness";
DoTheThing(msg.begin());
}
...or even worse:
void MyFunction()
{
std::string msg = "Hello, const correctness";
DoTheThing(const_cast<char*>(msg.c_str()));
}
neither of which, arguably, are 'better' than the original code. But because DoTheThing() was written in a const-incorrect way, you have to bend your code around it.
The meaning is that you guarantee to clients calling a const function member that the state of the object will not change. So when you say a member function is const it means that you do not change any of the objects member variables during the function call.
const, when attached to a non-static class method, tells the compiler that your function doesn't modify the internal state of the object.
This is useful in two ways:
If you do write code that changes internal state in your const method, the compiler catches the error, moving a programming error from run-time to compile-time.
If client code calls a non-const method on a constant pointer, the compiler catches the error, ensuring the "chain of not changing things" is maintained.
Typically you want to declare all non-mutating non-static class methods as const. This allows calling code to use the const qualifier on pointers, and it helps catch mistakes.
Typical C++: you can declare a class member variable "mutable" and then change it even from a const method.
The const keyword used after a method indicate that this method doesn't modify the object on which it's called. This way, this method can be called on a const version of the object.
If this is true, then should it be used everywhere, because i don't want ANY of the member variables to be altered or changed in any way?
Well, no. Sometimes you do want instance methods to modify members. For example, any set method will obviously need to set variables, so it's not the case that you should put const everywhere. But if your object's state is totally immutable, first consider whether it might not be better to have no instances at all (i.e., a static class), and if that's not the case, then make everything const.
It's quite unusual not to want to have any member variables changed, but if that's what your class requires, then you should make all your member functions const.
However, you probably do want to change at least some members:
class A {
private:
int val;
public:
A() : val(0) {}
void Inc() { val++; }
int GetVal() const { return val; };
};
Now if I create two instances of A:
A a1;
const A a2;
I can say:
a1.GetVal();
a2.GetVal();
but I can only say:
a1.Inc();
trying to change the value of a constant object:
a2.Inc();
gives a compilation error.