Is it possible to use the this pointer to assign the data from a calling object to one declared in a const member function? Something like:
(assuming I've already built SomeClass)
void func() const
{
SomeClass object1;
object1 = *this;
}
int main()
{
SomeClass object2;
object2.func();
return 0;
}
I know the above function is pointless. I'm just wondering if it's a legal assignment using *this.
This code is fine, so long as SomeClass has a copy assignment operator. The const on the member function declares that you will not change the state of the object: func() doesn't do this, so it is legal code. There are ways of subverting const if you try hard enough, however, this is not one of them.
Related
I have the following code which seems to work always (msvc, gcc and clang).
But I'm not sure if it is really legal. In my framework my classes may have "two constructors" - one normal C++ constructor which does simple member initialization and an additional member function "Ctor" which executes additional initialization code. It is used to allow for example calls to virtual functions. These calls are handled by a generic allocation/construction function - something like "make_shared".
The code:
#include <iostream>
class Foo
{
public:
constexpr Foo() : someConstField(){}
public:
inline void Ctor(int i)
{
//use Ctor as real constructor to allow for example calls to virtual functions
const_cast<int&>(this->someConstField) = i;
}
public:
const int someConstField;
};
int main()
{
//done by a generic allocation function
Foo f;
f.Ctor(12); //after this call someConstField is really const!
//
std::cout << f.someConstField;
}
Modifying const memory is undefined behaviour. Here that int has already been allocated in const memory by the default constructor.
Honestly I am not sure why you want to do this in the first place. If you want to be able to initalise Foo with an int just create an overloaded constructor:
...
constexpr Foo(int i) : someConstField{i} {}
This is completely legal, you are initalising the const memory when it is created and all is good.
If for some reason you want to have your object initalised in two stages (which without a factory function is not a good idea) then you cannot, and should not, use a const member variable. After all, if it could change after the object was created then it would no longer be const.
As a general rule of thumb you shouldn't have const member variables since it causes lots of problems with, for example, moving an object.
When I say "const memory" here, what I mean is const qualified memory by the rules of the language. So while the memory itself may or may not be writable at the machine level, it really doesn't matter since the compiler will do whatever it likes (generally it just ignores any writes to that memory but this is UB so it could do literally anything).
No.
It is undefined behaviour to modify a const value. The const_cast itself is fine, it's the modification that's the problem.
According to 7.1.6.1 in C++17 standard
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.
And there is an example (similar to yours, except not for class member):
const int* ciq = new const int (3); // initialized as required
int* iq = const_cast<int*>(ciq); // cast required
*iq = 4; // undefined: modifies a const object
If your allocation function allocates raw memory, you can use placement new to construct an object at that memory location. With this you must remember to call the destructor of the object before freeing the allocation.
Small example using malloc:
class Foo
{
public:
constexpr Foo(int i) : someConstField(i){}
public:
const int someConstField;
};
int main()
{
void *raw_memory = std::malloc(sizeof(Foo));
Foo *foo = new (raw_memory) Foo{3}; // foo->someConstField == 3
// ...
foo->~Foo();
std::free(foo);
}
I suggest, that you use the constructor to avoid the const cast. You commented, that after your call of Ctor the value of someConstField will remain const. Just set it in the constructor and you will have no problems and your code becomes more readable.
#include <iostream>
class Foo
{
public:
constexpr Foo(int i) : someConstField(Ctor(i)){}
int Ctor(); // to be defined in the implementation
const int someConstField;
};
int main()
{
Foo f(12);
std::cout << f.someConstField;
}
I know a const method cannot modify the object from which it is called. Look at this code:
class A{
int a;
public:
void f(A & a_) const {
a_.a=5;
};
};
int main(){
A x;
x.f(x);
return 0;
}
Why does this code compile? Why can I even assign a reference to a non const object of the same class, when declaring the method as constant? In general how can the compiler check all the possible situations in which the function could modify the object?
I know a const method cannot modify the object from which it is called.
This is an oversimplification, and slightly inaccurate.
A const function merely means that the implicit this pointer is a pointer to const.
Why does this code compile?
Because it is well-formed.
Why can I even assign a reference to a non const object of the same class, when declaring the method as constant?
Because constness of the function does not affect what objects you can modify through a reference.
In general how can the compiler check all the possible situations in which the function could modify the object?
The compiler simply does not make such checks.
A const member function cannot modify the object from which it is called using the "implicit" this parameter. f(...) is (ignoring member visibility) equivalent to the free function
void f(const A* this, A& _a) {
_a.a = 5;
}
If you pass the same object as a non-const pointer or reference, you are still allowed to modify it.
I searched for the answer to this question and wasn't able to find one. Consider the following code:
struct Foo
{
int *bar;
Foo(int barValue) : bar(new int(barValue)) {}
~Foo() { do_this(); }
void do_this() { delete bar; bar = nullptr; }
};
int main()
{
const Foo foo(7);
}
do_this() cannot be called on a const object, so I couldn't do something like foo.do_this(). It would also make sense in some situations to call do_this() outside of the destructor, which is why I don't want to simply include the code in the destructor definition. Because do_this() modifies a member variable, I can't declare it as const.
My question is: will the destructor be able to call do_this() on a const object when the object is destroyed?
I tried it and received no errors, but I want to make sure I'm not causing a memory leak once my program terminates.
Yes, you can certainly and safely call non-const functions from destructor. Standard explicitly allows this:
15.4/2 A destructor is used to destroy objects of its class type. The address
of a destructor shall not be taken. A destructor can be invoked for a
const, volatile or const volatile object. const and volatile semantics
([dcl.type.cv]) are not applied on an object under destruction. They
stop being in effect when the destructor for the most derived object
starts.
So say I was using this to create an object:
MyClass myObject;
and I had the function inside of the class to act upon the object. So one way could be using parameters, like this:
MyClass foo(MyClass a) {
return a;
}
Seems simple. But is there a way so I can use myObject.foo() and it would still return a even though I'm not using it as a parameter? One example could be some of the methods in std::string - you can use std::string.swap(), using the object for the swap() function.
Is there a way, or am I being stupid?
First off, keep in mind that you original code of
MyClass foo(MyClass a) {
return a;
}
does not actually return a. It returns a copy of a, which itself is a copy of whatever instance of MyClass you passed into foo. If you want to pass in a given object, act on it and return it, you need to use references, like so
MyClass & foo(MyClass & a) {
return a;
}
This will ensure that the a you get back from a call to foo is the exact same object you passed into it.
Additionally, an object can always return a reference to itself in one of its members...
class MyClass {
MyClass & foo() { return *this; }
}
This is especially useful in classes where you might want to chain a large number of operations together...
MyClass my = MyClass().foo().bar("Hello").baz(5);
Inside every member function is a magic secret parameter, which is a pointer to the object who's method was called, and the parameter's name is this.
MyClass& foo() { //returns reference to existing MyClass instead of making copies
this->print(); //call a different member
return *this; //return a reference to itself. Common for `operator=` and such.
}
Inside a class's (non-static) member function, you can use *this to name the object the function was called on.
So:
MyClass MyClass::foo() {
return *this;
}
(Notice that function returns a copy of the object. If you don't want a copy, use a reference as in #Jherico's answer.)
so I have a question about passing by reference. I tried passing an object to a member function by reference and have that member function call another member function with the reference I passed as an argument. However, the compiler says that the member function invoked is not found. Why is that so? The code below will describe my frustration in ways my words cannot express themself
// CODE 1
class someClass {
int data;
public:
someClass(someClass&);
someClass someFunction(const someClass&)
};
someClass::someClass(someClass &obj) {
data = obj.data;
}
someClass someClass::someFunction(const someClass &obj) {
someClass demo(obj); // <- this doesn't work
someClass demo(&obj); // <- neither does this
someClass demo(*obj); // <- or this
someClass demo2(*this); // <- this works though
}
Having a hard time understanding this, it may seem trivial but I do appreciate all the help I may get. Also, something mysterious has happened in xcode, when I tried the following (referring to CODE 2), it works. Any idea why?
// CODE 2
class someClass {
int data;
public:
someClass(someClass&);
void setData(int x) { data = x; }
};
int main() {
someClass first;
setData(10);
someClass second;
second = first;
//Mysteriously, it worked without overloading the '=' operator. Why?
//Also, I mentioned XCode just in case someone might say it's compiler specific
return 0;
}
The difficulties appear to be as follows:
someClass demo(obj);
You are trying to pass a const reference to a function that requires a reference that is not const. The typical pattern is to have a copy constructor take a const reference parameter, which avoids this problem.
someClass demo(&obj);
In this case, the compiler is looking for a constructor that takes a pointer to a someClass, but cannot find it. &obj returns a pointer to obj, not a reference to obj.
someClass demo(*obj);
In this case, you are attempting to dereference obj as if it was a pointer, but it is a reference, not a pointer.
someClass demo2(*this);
This works because you are dereferencing the this pointer, which points at an instance of someClass.