C++ Passing `this` into method by reference - c++

I have a class constructor that expects a reference to another class object to be passed in as an argument. I understand that references are preferable to pointers when no pointer arithmetic will be performed or when a null value will not exist.
This is the header declaration of the constructor:
class MixerLine {
private:
MIXERLINE _mixerLine;
public:
MixerLine(const MixerDevice& const parentMixer, DWORD destinationIndex);
~MixerLine();
}
This is the code that calls the constructor (MixerDevice.cpp):
void MixerDevice::enumerateLines() {
DWORD numLines = getDestinationCount();
for(DWORD i=0;i<numLines;i++) {
MixerLine mixerLine( this, i );
// other code here removed
}
}
Compilation of MixerDevice.cpp fails with this error:
Error 3 error C2664: 'MixerLine::MixerLine(const MixerDevice &,DWORD)' : cannot convert parameter 1 from 'MixerDevice *const ' to 'const MixerDevice &'
But I thought pointer values could be assigned to references, e.g.
Foo* foo = new Foo();
Foo& bar = foo;

this is a pointer, to get a reference you have to dereference (*this) it:
MixerLine mixerLine( *this, i );

You should dereference this, because this is a pointer, not a reference. To correct your code you should write
for(DWORD i=0;i<numLines;i++) {
MixerLine mixerLine( *this, i ); // Ok, this dereferenced
// other code here removed
}
Note: the second const at the constructor's parameter const MixerDevice& const parentMixer is completely useless.

To obtain a reference from a pointer you need to dereference the pointer, as it has already been mentioned. Additionally (maybe due to copying into the question?) the constructor should not compile:
const MixerDevice& const parentMixer
That is not a proper type, references cannot be const qualified, only the referred type can be, so the two (exactly equivalent) options are:
const MixerDevice& parentMixer
MixerDevice const& parentMixer
(Note that the const qualifying of MixerDevice can be done at either way, and it means exactly the same).

Pointer values can be assigned to pointers, but not to references!1
Foo* foo = new Foo();
Foo& bar = *foo;
^
^
1. Well, they can be used to initialise references-to-pointers, but that's not what you have here...

Related

C++ const problems when member value is changed from pointer to non-pointer

I have two classes TestClass and OtherClass, where TestClass has a member variable of type OtherClass named m_otherClass. Note that this is not declared to be const.
In the minimal example provided below; when m_otherClass is a pointer, then everything compiles and runs fine. If I change this to be a non-pointer, then I get compiler errors (the changes are commented out in the minimal example):
"Non-const function 'setOtherMember' is called on const object"
error: passing 'const OtherClass' as 'this' argument discards qualifiers [-fpermissive] m_otherClass.setOtherMember();
#include <iostream>
#include <memory>
class OtherClass {
public:
void setOtherMember() {
m_otherMember = 2;
std::cout << "Other member is now 2" << std::endl;
}
private:
int m_otherMember = 0;
};
class TestClass {
public:
TestClass(): m_otherClass(std::make_unique<OtherClass>())
// TestClass()
{}
void myMethod() const {
m_otherClass->setOtherMember();
// m_otherClass.setOtherMember();
}
private:
std::unique_ptr<OtherClass> m_otherClass;
// OtherClass m_otherClass; // If changing to this I get the error!!
};
int main() {
TestClass testClass;
testClass.myMethod();
return 0;
}
Is this because myMethod() is const (and then promising not to change any member variables), whereas setOtherMember() is non-const and is changing OtherClass's member variable, and then indirectly also the m_otherClass object?
But why does this not fail then when m_otherClass is a pointer?
And why does the compiler error says that passing 'const OtherClass' as 'this'argument fails, when m_otherClass has not been declared to be const?
Const qualified member functions in most cases aren't allowed to change an object's members state. This means, that every member which is not mutable can not be modified in this function body. When dealing with pointers, you just say, that you won't modify a pointer value, not a pointee itself. It is because constness of a pointer is not propagated on its pointee.
In the upcoming standards it will be possible to change this behaviour by using propagate_const.
A simpler example to demonstrate the difference.
struct Foo { int m; };
const Foo f = {10};
f.m = 20; // Not allowed since modifying f.m modifies f.
struct Bar { int* p; };
int i = 10;
int j = 20;
const Bar b = {&i};
b.p = &j; // Not allowed since modifying b.p modifies b.
*(b.p) = j; // Allowed since it does not change b or b.p. It changes the value
// of what b.p points to.
When you put const on a method, all your data members are treated as being const. And that is why you get the error when you have OtherClass as a value, since it turns into a value of const OtherClass.
Now when you use a pointer of OtherClass you get const std::unique_ptr<OtherClass> and the const applies only to the pointer but not to the value it points to.
But why does this not fail then when m_otherClass is a pointer?
Because it is const correct to modify an object pointed by a const pointer, as long as it is a pointer to non-const such as in your case.
And why does the compiler error says that passing 'const OtherClass' as 'this'argument fails, when m_otherClass has not been declared to be const?
myMethod is declared const. Therefore this is a pointer to const. Therefore the lvalue this->m_otherClass is also const regardless of whether the object named by the lvalue is const or not.

C++ Const Member Function (Beginner)

In C++ Primer P259, it says
Objects that are const, and references or pointers to const objects,
may call only const member functions.
Based on my current understanding, however, pointers to const objects not necessarily applies because the pointer itself is nonconst. As long as the member function does not modify the object being pointed to, it's legal to call nonconst member functions on pointers to const objects.
Is it correct?
Edit: OK I get it now, it is because when we "call member function on the pointer", we are actually dereferencing it first, and use the object underneath.
The quote is correct.
Try this
class TestClass
{
public:
void nonconst(){};
void constMethod() const {}
};
int main()
{
TestClass const *s = new TestClass();
//s->nonconst(); // (1) no not legal
s->constMethod();
s = new TestClass(); // (2) yes legal
s->constMethod();
}
s is a pointer to a constant. Calling a non const method causes
passing ‘const TestClass’ as ‘this’ argument discards qualifiers [-fpermissive]
However s can point to a different instance. As said in the comments the pointer can be pointed to a different variable.

const-pointer to non-const-pointer in constructor

I'm curious why the compiler doesn't complain if I hand over a const-pointer to a non-const-pointer as parameter in a constructor of a class that itself, which of course is at construction time not const.
#include <iostream>
class A
{
public:
A(int* v) : v(v) {}
int* v;
};
class B
{
public:
B() : o(23), v(&o) {}
const A cc() const
{
return A(v); //expected const to non-cosnt error here, but seems valid
}
int o;
int* v;
};
int main() {
B b;
const B* bc = &b;
A a = bc->cc();
*(a.v) = 25; // here I'm changing an originally const value
std::cout << b.o << std::endl;
return 0;
}
With defining cc() as const I expected the line where the return value is initialized an error message about converting a const to a non-const. The code-snippet compiles fine and in the end I get the output "25" even so that should have been const.
The A constructor expects a copy of a pointer instead of a reference. It is absolutely legal to copy a int * const into an int*. Therefore, no error occurs.
You should use references instead of pointers when you want a consistent behavior regarding constness. By the way, returning const objects is a bad idea.
You're confusing int const* (or const int*) and int* const.
Copying a const object into a non-const new object is fine, whether that object is a pointer or not. That's all you're doing here; the pointer itself is const (it's int* const), so you can pretty much do what you like with a copy of it.
What is not ok is copying a int const* into a int*, because now you're saying the thing being pointed to has magically lost its const-protection.
constness of an object does not propagate to constness of the pointee of a pointer member. The pointer becomes const but the pointee stays non-const. Even if the pointer is const, you can easily obtain a non-const pointer by simply copying the pointer which is exactly what happens as the pointer is passed by value.

C++: Error passing const pointer of const reference

I have C++ code that when I compile it I get the following error message:
error: no matching function for call to ‘DataSourceScheme::initObject(const QString&, const QString&, QVector<ColumnScheme*>* const&)’
initObject(datasourcescheme.name_, datasourcescheme.cmd_, datasourcescheme.columns_);
note: no known conversion for argument 3 from ‘QVector<ColumnScheme*>* const’ to ‘const QVector<const ColumnScheme*>*
The C++ code:
DataSourceScheme::DataSourceScheme(const DataSourceScheme &datasourcescheme) {
initObject(datasourcescheme.name_, datasourcescheme.cmd_, datasourcescheme.columns_);
}
void DataSourceScheme::initObject(const QString &name, const QString &cmd, const QVector<const ColumnScheme*> *columns) {
name_ = name;
cmd_ = cmd;
columns_ = new QVector<ColumnScheme*>();
if (columns != NULL) {
for (const ColumnScheme *column : *columns) {
addColumn(*column);
}
}
}
Please help
Thanks!
Perhaps you need clarification on the usage of const. foo* const A declares an object of type foo and creates a constant pointer to that object. The object can be changed but not the pointer. const foo* creates a pointer to a constant object. The object foo is not modifiable.
You are trying to pass a constant pointer to a list of editable objects to a function which requires a pointer to a list of constant objects. Do you see where this leads to problems? The usage within the function does not match the criteria set at the creation of the objects being passed.
You can pass a normal pointer to a function requiring a constant pointer. This conversion is OK, i.e.
void func(foo* const param); // Function declaration
foo* A;
func(A); // Function call OK
Also,
void func(foo* const param); // Function declaration
foo* const A;
func(A); // Function call OK
You cannot pass a pointer to a constant object to a function requiring a normal pointer. This conversion is OK, i.e.
void func(foo* param); // Function declaration
const foo* A;
func(A); // Error
I will add a side note. The use of void func(foo* const param); is good practice IMHO to signify that the function func is not expected to delete, manage memory, or reassign the pointer. This is why many microsoft API calls use the const keyword. They merely use the object but in no way manage it.

Should I const_cast "this" when a method only accepts Foo *const?

I have a class Foo which is in a self referencing tree-like structure (minimally):
class Foo {
public:
// Gets this child's position relative to it's parent.
int getPosition() const {
return parent->indexOf(this);
}
int indexOf(const Foo *const child) const {
return children.indexOf(child); // this line causes an error.
}
private:
Foo *parent;
QList<Foo *> children;
}
The line return children.indexOf(child) expects const T &value to be passed as per the QList docs, this resolves to Foo *const &value for my scenario.
In order for my getPosition() method to call my own indexOf() method it is required to have a signature of const Foo *child at minimum in order to pass this from a const method. (Since this is const Foo *const).
My code will not compile however as const Foo *const child cannot be cast to Foo *const child for QList::indexOf. Neither of my methods modify the object state so they should be const (i.e. I don't want to un-cost getPosition to receive a non-const this).
So the question is, how do I go from this in a const context (const Foo *const) to what QList::indexOf requires. Should I be const casting this inside getPosition since I know that my indexOf (and subsequent calls) will not mutate it?
Is there something else I should have done? Perhaps my design is faulty.
I think this is a perfectly reasonable use case for const_cast, however it's not this you need to const_cast, but child. In this case, QList::indexOf expects a constant pointer to a Foo (Foo* const) but child is a constant pointer to a constant Foo (const Foo* const). There is no implicit conversion from Foo* const to const Foo* const because that would remove the const-ness from the value being pointed to.
So, to fix your code I would change the line to
return children.indexOf(const_cast<Foo*>(child));
You know QList::indexOf is not going to modify whatever child points to, so this won't produce undefined behavior. I would however add a comment explaining why the const_cast is necessary.