#Question regarding const argument and member function

132 messages ยท Page 1 of 1 (latest)

tender groveBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question run !howto ask.

unborn solar
#

how did you declare GetBoardIndices in the header

fickle spire
#

xIndex and yIndex are private member variables

unborn solar
fickle spire
unborn solar
#

your return type is

const sf::Vector2i

which means the returned object is a constant

#

but this declaration shows that GetBoardIndices is editing fields accessed through the pointer this

fickle spire
unborn solar
#

if this was the C language, you would have:

fickle spire
unborn solar
#
struct MyThing
{
  //etc...
};

int getResult(MyThing* this)
{
  //do some edits
  //return result;
}

int getResult_const(const MyThing* this)
{
  //no edits allowed
  //return result;
}
unborn solar
fickle spire
#

So you cannot call a non-constant method with a constant instance?

unborn solar
#

so add the const at the end of the declaration

fickle spire
unborn solar
fickle spire
#

So when should I use only const before the method dec, vs after, vs both front and after?

unborn solar
#

do it

fickle spire
fickle spire
#
const sf::Vector2i GetBoardIndices() { return sf::Vector2i(xIndex, yIndex); }
```
unborn solar
#

since C++11 there is a way to declare a member function to be available only for lvalues or rvalues too, but that is another topic for a different time

unborn solar
fickle spire
#

If I call this method and edit the returned value, it won't change xIndex and yIndex which are the member vars.

unborn solar
#

for non-const objects it's fine

unborn solar
fickle spire
#

Yeah, I see that now, but just doesn't make sense imo XD If it returned a reference or ptr to the xIndex or yIndex directly, I would see it.

unborn solar
#

it makes sense

unborn solar
#

let me demonstrate

fickle spire
# unborn solar let me demonstrate

Just to clear this up, this method won't modify the xIndex and yIndex variables, correct? const sf::Vector2i GetBoardIndices() { return sf::Vector2i(xIndex, yIndex); } It only reads and copies from them.

unborn solar
# fickle spire Just to clear this up, this method won't modify the xIndex and yIndex variables,...
#include <iostream>
#include <thread>
#include <xmmintrin.h>

class Demo
{
    int x;
    
    public:
    Demo() : x(4)
    {
        
    }
        
    int func0()
    {
        return this->x;
    }
    
    const int func1()
    {
        return this->x;
    }
    
    
    
    int func2() const
    {
        return this->x;
    }
    
    const int func3() const
    {
        return this->x;
    }
    
};

int main() {
     
     Demo d1;
     const Demo d2;
     
     int result = d1.func0();
     result = d1.func1();
     result = d1.func2();
     result = d1.func3();
     
     //result = d2.func0(); //does not compile
     //result = d2.func1(); //does not compile
     result = d2.func2();
     result = d2.func3();
     
}
#
main.cpp:20:18: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
  const int func1()
                  ^

main.cpp:32:20: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
  const int func3() const
                    ^
main.cpp: In function 'int main()':
main.cpp:44:7: warning: variable 'result' set but not used [-Wunused-but-set-variable]
   int result = d1.func0();
       ^
unborn solar
fickle spire
unborn solar
fickle spire
#

Yes, I get that. Const objects can only call const methods. I guess the language is just designed that way then. The reason I was getting confused is because I've just thought const objects couldn't be modified using the "=" operator and since this isn't assigning anything to or writing to the actual const object, it would be fine.

unborn solar
#
So I still don't understand why it won't allow it. 

it won't compile because

int main()
{
  int value = 20;
  const int* ptr2 = &value;
  int* ptr1 = ptr2;
  *ptr1 = 40;
}

you can't edit things through a const pointer

#

@fickle spire

#
So this will mean that it is IMPOSSIBLE for the function to modify the member values, correct?

C++ does not have the ability to guess what is possible and what is not, it can only read what you declared

#

and from there decide exactly what is possible and what is not

#

no matter what you think

#

in your example, from the variable const Tile& _tile, trying to call the function _tile.GetBoardIndices() means that the type of the this pointer is const Tile*

fickle spire
#

Ah okay. Makes sense.

#

Oh right. A reference is just a pointer to the address aswell.

unborn solar
#

so it tries to find a matching function which has the this pointer declared as const Tile*

#

but you see, that function does nto exist - only Tile* exists

unborn solar
fickle spire
#

Okay, thanks!

#

!solved

tender groveBOT
#

Thank you and let us know if you have any more questions!

unborn solar
# fickle spire Okay, thanks!

one way to hack you way out of const correctness (when some idiot you work with in the office wrote some class and forgot to add const to the functions) is to use const_cast, but that is very complicated, very difficult to get it right, and shows that the code is spaghetti

fickle spire
unborn solar
#

skip these for now, they are cancer

fickle spire
unborn solar
#

come back in a few years

fickle spire
#

it's more efficient to use a specified cast instead of c-style cast since c-style does multiple, right?

unborn solar
#

only dynamic_cast is decided at runtime when using virtual functions through a pointer

fickle spire
#

yeah, so I guess it depends on the compiler (except dynamic cast)

unborn solar
#

static_cast is your typical arithmetic conversion like from double to int or from char to int

#

const_cast is a hack

#

reinterpret_cast is "hey, grab that piece of memory and pretend that something else lives there at those bytes"

fickle spire
unborn solar
#

the first one takes the char array with size 1 byte and treats that memory address as an int variable, and returns it as a copy in x, you are reading outside the bounds of the array, this is undefined behavior

fickle spire
#

Yeah, ofcourse xd

unborn solar
#

and the second one, is taking the address where the char array lives, no one knows where, and treats the address as a number, an int

#

both are cursed

#

do not use them

fickle spire
#

yeah. both "h" are only stored in memory while copying and then removed from the stack. but whatever

#

no reason to do this obviously

unborn solar
#

there is no out of bounds reading or anything

fickle spire
unborn solar
#
'h'

this is a char literal

fickle spire
#

Oh, right. This aint C

unborn solar
fickle spire
#

is it? whats the diff between c-string literal and char?

unborn solar
#

works for C and C++ the same way

fickle spire
#

oh, I get it. " always adds a null-determinant while ' doesnt.

unborn solar
#

the variable letter is a char

fickle spire
#

yeah. just didn't know it added a null determinant and thus actually returns an array

#

well, the more you know. learned a lot that I've never had to learn/use before ๐Ÿ˜›

unborn solar
fickle spire
unborn solar
#

in code?

fickle spire
#

The d3d11 and 12 api:s, yes. currently learning 12 thought, since it's just a more complex version where you have to manage resources, and gpu/cpu synchronization manually. In d3d11 the drivers does that for you.

unborn solar
#

like references, like deep copying, like virtual functions

fickle spire
#

I've actually almost only worked with C++. From our convo, it might seem like I have no idea of things, but I've done a lot of programs etc. I've only not bothered learning the actual meaning of l/r-values and constants and similar small stuff, since I know how to use them to build what I want (except with const in this case).

unborn solar
fickle spire
#

Here's my first ecs i did. Will optimize it in the future thought, since the constant lookup for the component will add a lot of time.

unborn solar
#

what guide do you follow when learning C++?

fickle spire
fickle spire
fickle spire
unborn solar
fickle spire
# unborn solar your code is executed on the machine of the customers which buy the software pro...

And? That's what learning and improving will remove? I'm capable of writing code, but it won't be perfect since I'm still relatively new compared to other people working. Not knowing one case of how to use constant member functions makes me incapable of writing decent code? If it's a problem it will maybe even be removed or changed during the code review before pushing it to the development branch etc.

unborn solar
#

if yes, listen to them

#

if no, you are on your own to learn

fickle spire
fickle spire
unborn solar
#

that's not a toxic mentality

#

C++ is a dangerous language just like C

#

because pointers

fickle spire
#

But how you use "๐Ÿ’€ " and how you're building your sentences are just plain rude, and that's not even a debate.

#

And please don't help me next time. Would rather have someone who helps and then are nice.

unborn solar
#

In the header you sent me I found one bug and one dangerous function which can easily cause bugs

#

first, line 143

    /** @brief A pure virtual function that should be implemented for an inheriting subclass. It should operate on the bound Entity objects, but that isn't mandatory.
    */
    virtual void Update() = 0;
};
#

your class does not have a virtual destructor, which means that using runtime polymorphism, depending on the fields of the derived classes, can cause the wrong destructor to be called, meaning memory leaks

#

and next, line 390

template<typename T>
inline T* BiDirectionalMap<T>::GetObjectByID(int _id)
{
    return &objects[idToIndex.at(_id)];
}

if you use the pointer returned by this function without editing the vector's capacity this->objects, the pointer will be valid, but if someone edits the capacity, trying to read from the pointer will be a read after free bug, likely crash

#

just like this snippet:

#include <iostream>
#include <vector>
#include <string>

int main() {
     std::vector<std::string> elements = {"test1", "test2", "test3"};
     std::string* ptr = &elements[0];
     
     for(int i = 0; i < 20; ++i)
     {
         elements.push_back(std::string(i,'A'));
     }
     
     std::cout<<*ptr<<"\n";
}
#

I do not have context for your use of this function, consider writing something like

template<typename T>
void BiDirectionalMap<T>::SetObjectByID(int _id, const T& value)
{
  objects[idToIndex.at(_id)] = value;
}

template<typename T>
T BiDirectionalMap<T>::GetObjectByID(int _id) const
{
    return objects[idToIndex.at(_id)];
}