String::~String() {
std::cout<<"String()" <<std::endl;
}
I wonder if this implementation of destructor is valid?
And another question about const member function qualifier, I know the const function can not change the variables in this class, it just read-only. If there is no other weird questions about it, I think I can understand it, but I saw some questions as following:
It allows the invocation of a non-const member function for the object pointed to by this
It guarantees that only mutable member variables of the object pointed to by this can be changed
It ensures that all constants remain invariable
It prevents inheritance
It allows changes to the state of the object pointed to by this
Based on my understanding, it is very hard to check which one is right, so I guess all of them are wrong?
The destructor is technically just another function, there doesn't seem anything wrong syntactically with this destructor to me, so it seems valid
That is all there is to const member functions, you cannot modify the data. These functions are automatically invoked by a const instance of the class. So if you have two functions with the same signature except for const-ness, it will chose the const version for const instances, and for non-const instances, it will depend on how you use it that determines which version is invoked
a) you cannot invoke non-const member functions within a const member function
b)Correct
c) correct
d) i'm unsure what you mean by preventing inheritance. IF you declare a function as virtual, const or not, it is inherited and can be overridden by subclasses
e) in const member functions, all data is considered const, unless declared a mutable.
Yes, that is a valid destructor.
const does not prevent inheritance. Nor does it bring about invariant behavior in the class's methods.
This question is actually multiple questions, though.
I recommend reading C++ FAQS.
I wonder if this implementation of destructor is valid?
There is nothing wrong with the destructor. But the question is: is that all you want to do in the destructor? Destructor is usually used to free the resources object holds when its alive; so it should free them when its going to die, so that others can use them. If it doesn't free them, then those resources will not be used by others as long as the program runs. Such a situation is usually referred to as Resource Leak, and if the resource is memory, its called Memory Leak.
Regarding question 2.
A nice way to think of member function cv qualifiers is to think of them as qualifiers on the 'this' pointer.
For example, if we wrote some C++ code in C:
class A
{
public:
void f1 ();
void f2 () const;
private:
int i;
};
This is the same as the following C code:
struct A
{
int i;
};
void f1 (A * const this); // Non const member
void f2 (A const * const this); // Const member
Another important thing to understand is that when you refer to a non static data member of a class, (*this). is implicitly added to it:
void A::f1 ()
{
i = 0; // This and the next line have the same meaning
(*this).i = 0;
}
When the member function is const, the this pointer is declared as pointing to a const object:
void A::f2 () const
{
(*this).i = 0; // Error '*this' is const, so cannot modify (*this).i
}
One of the conclusions from this, and something that people sometimes find is surprising, is that a const member function can still modify data pointed to by a member pointer. For example:
class A
{
public:
void f () const
{
*i = 0;
}
private:
int * i;
};
This looks wrong, but it's actually fine. (*this).i is const and so you would not be able to change what i points to, but i is still a pointer to a non const int and so we can modify the value pointed to by i.
Related
Consider the following code snippet:
class A
{
public:
void nonConstFun()
{
}
};
class B
{
private:
A a_;
A * pA_;
public:
void fun() const
{
pA_->nonConstFun();
//a_.nonConstFun(); // Gives const related error
}
};
int main()
{
B b;
b.fun();
}
Here I am expecting the compiler to fail the compilation for lack of constness for calling A::nonConstFun() inside B::fun() irrespective of the type of A object.
However the compiler complains for the object, but not for the pointer. Why?
I am using VS2017 on Windows 10.
The other answers explain the T* const vs T const * which is what is happening. But it is important to understand the implication of this beyond just the mere syntax.
When you have a T* inside a structure the pointer is inside the object (part of the layout of the objet), but the pointed object is physically outside of the structure. That is why a const object with a T* member is not allowed to modify the pointer, but it is allowed to modify the pointed object - because physically the pointed object is outside the enclosing object.
And it is up to the programmer to decide if the pointed object is logically part of the enclosing object (and as such should share constness with the enclosing) or if it is logically an external entity. Examples of former include std::vector, std::string. Examples of the latter include std::span, std::unique_ptr, std::shared_ptr. As you can see both designs are usefull.
The shortcoming of C++ is that it doesn't offer an easy way to express a logical constness as stated above (what you actually expected from your code).
This is known and for this exact purpose there is an experimental class which is not yet standard propagate_const
std::experimental::propagate_const is a const-propagating wrapper for
pointers and pointer-like objects. It treats the wrapped pointer as a
pointer to const when accessed through a const access path, hence the
name.
struct B
{
A a_;
std::experimental::propagate_const<A *> pA_;
void fun()
{
pA_->nonConstFun(); // OK
}
void fun() const
{
// pA_->nonConstFun(); // compilation error
}
};
It is enforced.
If you try changing the pointer, the compiler will not let you.
The thing that the pointer points to, however, is a different conversation.
Remember, T* const and T const* are not the same thing!
You can protect that by either actually making it A const*, or simply by writing your function in the manner that is appropriate.
I am trying to understand c++'s const semantics more in depth but I can't fully understand what really the constness guarantee worth is.
As I see it, the constness guarantees that there will be no mutation, but consider the following (contrived) example:
#include <iostream>
#include <optional>
#include <memory>
class A {
public:
int i{0};
void foo() {
i = 42;
};
};
class B {
public:
A *a1;
A a2;
B() {
a1 = &a2;
}
void bar() const {
a1->foo();
}
};
int main() {
B b;
std::cout << b.a2.i << std::endl; // output is 0
b.bar();
std::cout << b.a2.i << std::endl; // output is 42
}
Since bar is const, one would assume that it wouldn't mutate the object b. But after its invocation b is mutated.
If I write the method foo like this
void bar() const {
a2.foo();
}
then the compiler catches it as expected.
So it seems that one can fairly easily circumvent the compiler with pointers. I guess my main question is, how or if I can be 100% sure that const methods won't cause any mutation to the objects they are invoked with? Or do I have completely false expectations about const?
Why does c++ allow invocation of non-const methods over pointers in const methods?
EDIT:
thanks to Galik's comment, I now found this:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4372.html
Well, this was exactly what I was looking for! Thanks!
And I find Yakk's answer also very helpful, so I'll accept his answer.
const tells the caller "this shouldn't mutate the object".
const helps the implementor with some errors where accidentally mutating state generates errors unless the implementor casts it away.
const data (not references, actual data) provides guarantees to the compiler that anyone who modifies this data is doing undefined behaviour; thus, the compiler is free to assume that the data is never modified.
const in the std library makes certain guarantees about thread safety.
All of these are uses of const.
If an object isn't const, anyone is free to const_cast away const on a reference to the object and modify it.
If an object is const, compilers will not reliably diagnose you casting away const, and generating undefined behavior.
If you mark data as mutable, even if it is also marked as const it won't be.
The guarantees that the std provides based off const are limited by the types you in turn pass into std following those guarantees.
const doesn't enforce much on the programmer. It simply tries to help.
No language can make a hostlie programmer friendly; const in C++ doesn't try. Instead, it tries to make it easier to write const-correct code than to write const-incorrect code.
Constness by itself doesn't guarantee you anything. It only takes away rights of specific code to mutate an object through a specific reference. It doesn't take away rights of other code to mutate the same object through other references, right under your feet.
So it seems that one can fairly easily circumvent the compiler with pointers.
That is indeed true.
I guess my main question is, how or if I can be 100% sure that const methods won't cause any mutation to the objects they are invoked with?
The language guarantees that only in a local sense.
Your class is, indirectly, the same as the following:
struct Foo
{
int* ptr;
Foo() : ptr(new int(0)) {};
void bar() const { *ptr = 10; }
};
When you use:
Foo f;
f.bar();
the member variable of f did not change since the pointer still points to the location after the call to f.bar() as it did before the call. In that sense, f did not change. But if you extend the "state" of f to include the value of what f.ptr points to, then the state of f did change. The language does not guarantee against such changes.
It's our job, as designers and developers, to document the "const" semantics of the types we create and provide functions that preserve those semantics.
Or do I have completely false expectations about const?
Perhaps.
When a class method is declared as const, that means the implicit this pointer inside the method is pointing at a const object and thus the method cannot alter any of the members of that object (unless they are explicitly declared as mutable, which is not the case in this example).
The B constructor is not declared as const, so this is of type B*, ie a pointer to a non-const B object. So a1 and a2 are non-const, and a1 is declared as a pointer to a non-const A object, so the compiler allows a1 to be pointed at a2.
bar() is declared as const, so this is of type const B*, ie a pointer to a const B object.
When bar() calls a1->foo(), a1 is const by virtue of this pointing at a const B object, so bar() can't change a1 to point at something else. But the A object that a1 is pointing at is still deemed to be non-const by virtue of a1's declaration, and foo() is not declared as const, so the compiler allows the call. However, the compiler can't validate that a1 is actually pointing at a2, a member of B that is supposed to be const inside of bar(), so the code breaks the const contract and has undefined behavior.
When bar() tries to call a2.foo() instead, a2 is const by virtue of this pointing at a const B object, but foo() is not declared as const, so the compiler fails the call.
const is just a safety catch for well-behaving code. It does not stop you from shooting yourself in the foot by using misbehaving code.
This is a correct observation. In const-qualified functions (bar in your example) all data members of the class are behaving as if they are const data members when accessed from this function. With pointers, it means that the pointer itself is constant, but not the object it points to. As a matter of fact, your example can be very much simplified into:
int k = 56;
int* const i = &k;
*i = 42;
There is a big difference between pointer to constant object and constant pointer, and one needs to understand it, so that 'promises', which were not given in the first place, would not seem to be broken.
I understand that having a const method in C++ means that an object is read-only through that method, but that it may still change otherwise.
However, this code apparently changes an object through a const reference (i.e. through a const method).
Is this code legal in C++?
If so: Is it breaking the const-ness of the type system? Why/why not?
If not: Why not?
Note 1: I have edited the example a bit, so answers might be referring to older examples.
Edit 2: Apparently you don't even need C++11, so I removed that dependency.
#include <iostream>
using namespace std;
struct DoBadThings { int *p; void oops() const { ++*p; } };
struct BreakConst
{
int n;
DoBadThings bad;
BreakConst() { n = 0; bad.p = &n; }
void oops() const { bad.oops(); } // can't change itself... or can it?
};
int main()
{
const BreakConst bc;
cout << bc.n << endl; // 0
bc.oops(); // O:)
cout << bc.n << endl; // 1
return 0;
}
Update:
I have migrated the lambda to the constructor's initialization list, since doing so allows me to subsequently say const BreakConst bc;, which -- because bc itself is now const (instead of merely the pointer) -- would seem to imply (by Stroustrup) that modifying bc in any way after construction should result in undefined behavior, even though the constructor and the caller would have no way of knowing this without seeing each others' definitions.
The oops() method isn't allowed to change the constness of the object. Furthermore it doesn't do it. Its your anonymous function that does it. This anonymous function isn't in the context of the object, but in the context of the main() method which is allowed to modify the object.
Your anonymous function doesn't change the this pointer of oops() (which is defined as const and therefore can't be changed) and also in no way derives some non-const variable from this this-pointer. Itself doesn't have any this-pointer. It just ignores the this-pointer and changes the bc variable of the main context (which is kind of passed as parameter to your closure). This variable is not const and therefore can be changed. You could also pass any anonymous function changing a completely unrelated object. This function doesn't know, that its changing the object that stores it.
If you would declare it as
const BreakConst bc = ...
then the main function also would handle it as const object and couldn't change it.
Edit:
In other words: The const attribute is bound to the concrete l-value (reference) accessing the object. It's not bound to the object itself.
You code is correct, because you don't use the const reference to modify the object. The lambda function uses completely different reference, which just happen to be pointing to the same object.
In the general, such cases does not subvert the type system, because the type system in C++ does not formally guarantee, that you can't modify the const object or the const reference. However modification of the const object is the undefined behaviour.
From [7.1.6.1] The cv-qualifiers:
A pointer or reference to a cv-qualified type need not actually point
or refer to a cv-qualified object, but it is treated as if it does; a
const-qualified access path cannot be used to modify an object even if
the object referenced is a non-const object and can be modified through
some other access path.
Except that any class member declared mutable (7.1.1) can be modified,
any attempt to modify a const object during its lifetime (3.8) results
in undefined behavior.
I already saw something similar. Basically you invoke a cost function that invoke something else that modifies the object without knowing it.
Consider this as well:
#include <iostream>
using namespace std;
class B;
class A
{
friend class B;
B* pb;
int val;
public:
A(B& b);
void callinc() const;
friend ostream& operator<<(ostream& s, const A& a)
{ return s << "A value is " << a.val; }
};
class B
{
friend class A;
A* pa;
public:
void incval() const { ++pa->val; }
};
inline A::A(B& b) :pb(&b), val() { pb->pa = this; }
inline void A::callinc() const { pb->incval(); }
int main()
{
B b;
const A a(b); // EDIT: WAS `A a(b)`
cout << a << endl;
a.callinc();
cout << a << endl;
}
This is not C++11, but does the same:
The point is that const is not transitive.
callinc() doesn't change itself a and incval doesn't change b.
Note that in main you can even declare const A a(b); instead of A a(b); and everything compile the same.
This works from decades, and in your sample you're just doing the same: simply you replaced class B with a lambda.
EDIT
Changed the main() to reflect the comment.
The issue is one of logical const versus bitwise const. The compiler
doesn't know anything about the logical meaning of your program, and
only enforces bitwise const. It's up to you to implement logical const.
This means that in cases like you show, if the pointed to memory is
logically part of the object, you should refrain from modifying it in a
const function, even if the compiler will let you (since it isn't part
of the bitwise image of the object). This may also mean that if part of
the bitwise image of the object isn't part of the logical value of the
object (e.g. an embedded reference count, or cached values), you make it
mutable, or even cast away const, in cases where you modify it without
modifying the logical value of the object.
The const feature merely helps against accidental misuse. It is not designed to prevent dedicated software hacking. It is the same as private and protected membership, someone could always take the address of the object and increment along the memory to access class internals, there is no way to stop it.
So, yes you can get around const. If nothing else you can simply change the object at the memory level but this does not mean const is broken.
This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
What is the meaning of a const at end of a member function?
about const member function
I found one function prototype as under:
const ClassA* ClassB::get_value() const
What does the above statement signify? Can I change the member of ClassA object?
The first const means what it returns is a pointer to const A. So no, you can't change what it returns (unless you cast away the const-ness, which will give undefined behavior if the object it returns is actually defined as const, rather than returning a const pointer to an object that itself wasn't defined as const).
The second const means that get_value can't change any of the (non-mutable) state of the ClassB on which it's invoked (among other things, it's transitive, so ClassB::get_value can only call other member functions that are also const-qualified).
No.
The ClassA pointer returned by that function is marked const. That means that you should not change any of its values.
It won't be impossible to change the values because there are various ways to get around a const marking, but you are clearly not meant to be changing it.
What does the above statement signify? Can i change the member of ClassA object.
get_value is a const member function of ClassB so it cannot modify any non-mutable data members of ClassB inside its definition. But it can however modify members of ClassA
For example the following compiles (leaks memory but that is not much of a concern here)
struct A{
int x;
};
struct B
{
const A* get_value() const
{
A *p= new A;
p->x = 12;
return p;
}
};
get_value() is a read-only function that does not modify the ClassB object for which it is called. It returns a read-only pointer to a ClassA object. You can modify the object pointed to by this object by casting away its constness using const_cast. But the ideal thing to do is to make a copy of this object and mutate that.
I understand that the function is not allowed to change the state of the object, but I thought I read somewhere that the compiler was allowed to assume that if the function was called with the same arguments, it would return the same value and thus could reuse a cached value if it was available. e.g.
class object
{
int get_value(int n) const
{
...
}
...
object x;
int a = x.get_value(1);
...
int b = x.get_value(1);
then the compiler could optimize the second call away and either use the value in a register or simply do b = a;
Is this true?
const is about program semantics and not about implementation details. You should mark a member function const when it does not change the visible state of the object, and should be callable on an object that is itself const. Within a const member function on a class X, the type of this is X const *: pointer to constant X object. Thus all member variables are effectively const within that member function (except mutable ones). If you have a const object, you can only call const member functions on it.
You can use mutable to indicate that a member variable may change even within a const member function. This is typically used to identify variables used for caching results, or for variables that don't affect the actual observable state such as mutexes (you still need to lock the mutex in the const member functions) or use counters.
class X
{
int data;
mutable boost::mutex m;
public:
void set_data(int i)
{
boost::lock_guard<boost::mutex> lk(m);
data=i;
}
int get_data() const // we want to be able to get the data on a const object
{
boost::lock_guard<boost::mutex> lk(m); // this requires m to be non-const
return data;
}
};
If you hold the data by pointer rather than directly (including smart pointers such as std::auto_ptr or boost::shared_ptr) then the pointer becomes const in a const member function, but not the pointed-to data, so you can modify the pointed-to data.
As for caching: in general the compiler cannot do this because the state might change between calls (especially in my multi-threaded example with the mutex). However, if the definition is inline then the compiler can pull the code into the calling function and optimize what it can see there. This might result in the function effectively only being called once.
The next version of the C++ Standard (C++0x) will have a new keyword constexpr. Functions tagged constexpr return a constant value, so the results can be cached. There are limits on what you can do in such a function (in order that the compiler can verify this fact).
The keyword mutable on member variables allows for const functions to alter the state of the object at hand.
And no, it doesn't cache data (at least not all calls) since the following code is a valid const function that changes over time:
int something() const { return m_pSomeObject->NextValue(); }
Note that the pointer can be const, though the object pointed to is not const, therefore the call to NextValue on SomeObject may or may not alter it's own internal state. This causes the function something to return different values each time it's called.
However, I can't answer how the compiler works with const methods. I have heard that it can optimize certain things, though I'd have to look it up to be certain.
No.
A const method is a method that doesn't change the state of the object (i.e. its fields), but you can't assume that given the same input, return value of a const method is determined. In other words, const keyword does NOT imply that the function is one-to-one. For instance a method that returns the current time is a const method but its return value changes between calls.
The const keyword on a member function marks the this parameter as constant. The function can still mute global data (so can't be cached), but not object data (allowing for calls on const objects).
In this context, a const member function means that this is treated as a const pointer also. In practical terms, it means you aren't allowed to modify the state of this inside a const member function.
For no-side-effect functions (i.e., what you're trying to achieve), GCC has a "function attribute" called pure (you use it by saying __attribute__((pure))): http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
I doubt it, the function could still call a global function that altered the state of the world and not violate const.
On top of the fact that the member function can modify global data, it is possible for the member function to modify explicitly declared mutable members of the object in question.
Corey is correct, but bear in mind that any member variables that are marked as mutable can be modified in const member functions.
It also means that these functions can be called from other const functions, or via other const references.
Edit: Damn, was beaten by 9 seconds.... 9!!! :)
const methods are also allowed to modify static locals. For example, the following is perfectly legal (and repeated calls to bar() will return increasing values - not a cached 0):
class Foo
{
public:
int bar() const
{
static int x = 0;
return x++;
}
};