I'm having this problem with C++ classes. I would like to get pointer to myBar object and store it in quxBar. The reason is I would like to be able to check the value using quxBar->getX() but I would also like to prevent from accidentally modyfing it from Qux so I tried using Bar const*.
class Bar
{
private:
int x;
public:
void setX(int X) { x = X; };
int getX(){ return x };
}
class Foo
{
private:
Bar *myBar;
public:
Bar const* getPointerToBar(){ return myBar; };
}
class Qux
{
void myMethod();
Bar const* quxBar;
Foo *mainFoo;
}
void Qux::myMethod()
{
quxBar = mainFoo->getPointerToBar();
std::cout << quxBar->getX();
quxBar->setX(100); // HERE!!!
std::cout << quxBar->getX(); // returns 100
}
Unfortunatelly it doesn't work since I'm still able to perform quxBar->setX(100) with no compilation error.
Probably my approach is totally wrong, but using current "skills" :) I have no idea how to fix it.
Thanks in advance for any help and suggestions.
I don't think this is your actual code, firstly due to the syntax errors it has, and secondly due to the fact that it actually is correct (mostly). More specifically, with this piece of code, quxBar->setX(100); would result in compilation error.
However, quxBar->getX() would also be a compilation error, you need to tell the compiler that can be called on const objects, you do this by adding const at the end of the function signature:
int getX() const { return x; }
Perhaps in your actual code you had Bar* const quxBar instead of Bar const* quxBar; they mean two different things: The former is a const pointer to Bar, while the later is a pointer to const Bar. Eg. in the earlier case, only the pointer itself can't be modified, but the object it points to can.
Related
I am new to C++ and this might sound very basic. The compiler always looks at the method that returns a const pixel value for me, which I do not want it to bc I want to change the value of the returned pixel. This situation does not happen during my previous assignments but it happens this time. Is there any way to resolve this? Thank you so much.
provided PNG class:
const HSLAPixel & getPixel(unsigned int x, unsigned int y) const;
HSLAPixel & getPixel(unsigned int x, unsigned int y);
my code:
HSLAPixel & original = png_.getPixel((*it).x, (*it).y);
They aren't quite the same. One is declared const. The other one is non-const. The compiler will use the const version when your PNG is marked const and the non-const version otherwise.
I did this:
#include <iostream>
class Foo {
public:
void foo(int i) const { std::cout << "Const version.\n"; }
void foo(int i) { std::cout << "Non-const version.\n"; }
void myFunction() const { foo(10); }
};
int main() {
Foo foo;
foo.foo(10);
foo.myFunction();
}
When I run it, the first call to foo() prints the Non-const message, and the second one prints the const message.
This question already has answers here:
How do I remove code duplication between similar const and non-const member functions?
(21 answers)
C++ template to cover const and non-const method
(7 answers)
Closed 5 years ago.
Is there any advantage using one over the other:
class Foo
{
public:
const int& get() const
{
// stuff here
return myInt;
}
int& get()
{
return const_cast<int&>(static_cast<const Foo*>(this)->get());
}
};
Or
class Foo
{
public:
int& get()
{
// stuff here
return myInt;
}
const int& get() const
{
return const_cast<Foo*>(this)->get();
}
};
I only used the first one, but I just saw the second one used somewhere, so I am wondering.
The comment // stuff here could be a non-trivial check like retrieving the index of a table in order to return a ref on a member of the table (for example: myInt = myTable[myComputedIndex];) so I cannot just make it public. Thus table and any member are not const.
If you have to make a function that is const-agnostic, and avoids duplication, one neat way to do it is delegating implementation to a template, for example
class Foo {
private:
int my_int;
template <typename ThisPtr>
static auto& get(ThisPtr this_ptr) {
return this_ptr->my_int;
}
public:
int& get() {
return get(this);
}
const int& get() const {
return get(this);
}
};
This way you are free from the fear associated with using const_cast, mutable and other stuff that goes into trying to reduce code duplication in cases like this. If you get something wrong, the compiler will let you know.
Ignoring the issue of whether you really need a getter, the best solution when duplicating functionality in both a const and non-const method is to have the non-const method call the const method and cast away the const-ness of the result (i.e. the first of the two alternatives you present in the question).
The reason is simple: if you do it the other way around (with the logic in the non-const method), you could accidentally end up modifying a const object, and the compiler won't catch it at compile time (because the method is not declared const) - this will have undefined behaviour.
Of course this is only a problem if the "getter" is not actually a getter (i.e. if it is doing something more complicated than just returning a reference to a private field).
Also, if you are not constrained to C++11, the template-based solution presented by Curious in their answer is another way of avoiding this problem.
Is there any advantage using one over the other: ...
No, both are bad because they violate the data encapsulation principle.
In your example you should rather make myInt a public member.
There's no advantage to have getters for such case at all.
If you really want (need) getter and setter functions these should look like this:
class Foo
{
private:
mutable int myInt_;
// ^^^^^^^ Allows lazy initialization from within the const getter,
// simply omit that if you dont need it.
public:
void myInt(int value)
{
// Do other stuff ...
myInt = value;
// Do more stuff ...
}
const int& myInt() const
{
// Do other stuff ...
return myInt_;
}
}
You don't say where myInt comes from, the best answer depends on that.
There are 2+1 possible scenarios:
1) The most common case is that myInt comes from a pointer internal to the class.
Assuming that, this is the best solution which avoids both code duplication and casting.
class Foo{
int* myIntP;
...
int& get_impl() const{
... lots of code
return *myIntP; // even if Foo instance is const, *myInt is not
}
public:
int& get(){return get_impl();}
const int& get() const{return get_impl();}
};
This case above applies to pointer array, and (most) smart pointers.
2) The other common case is that myInt is a reference or a value member, then the previous solution doesn't work.
But it is also the case where a getter is not needed at all.
Don't use a getter in that case.
class Foo{
public:
int myInt; // or int& myInt;
};
done! :)
3) There is a third scenario, pointed by #Aconcagua, that is the case of an internal fixed array. In that case it is a toss-up, it really depends what you are doing, if finding the index is really the problem, then that can be factored away. It is not clear however what is the application:
class Foo{
int myInts[32];
...
int complicated_index() const{...long code...}
public:
int& get(){return myInts[complicated_index()];}
const int& get() const{return myInts[complicated_index()];}
};
My point is, understand the problem and donĀ“t over engineer. const_cast or templates are not needed to solve this problem.
complete working code below:
class Foo{
int* myIntP;
int& get_impl() const{
return *myIntP; // even if Foo instance is const, *myInt is not
}
public:
int& get(){return get_impl();}
const int& get() const{return get_impl();}
Foo() : myIntP(new int(0)){}
~Foo(){delete myIntP;}
};
#include<cassert>
int main(){
Foo f1;
f1.get() = 5;
assert( f1.get() == 5 );
Foo const f2;
// f2.get() = 5; // compile error
assert( f2.get() == 0 );
return 0;
}
As you intend access to more complex internal structures (as clarified via your edit; such as providing an operator[](size_t index) for internal arrays as std::vector does), then you will have to make sure that you do not invoke undefined behaviour by modifying a potentially const object.
The risk of doing so is higher in the second approach:
int& get()
{
// stuff here: if you modify the object, the compiler won't warn you!
// but you will modify a const object, if the other getter is called on one!!!
return myInt;
}
In the first variant, you are safe from (unless you do const_cast here, too, which now would really be bad...), which is the advantage of this approach:
const int& get() const
{
// stuff here: you cannot modify by accident...
// if you try, the compiler will complain about
return myInt;
}
If you actually need to modify the object in the non-const getter, you cannot have a common implementation anyway...
Modifying a const object through a non-const access path [...] results in undefined behavior.
(Source: http://en.cppreference.com/w/cpp/language/const_cast)
This means that the first version can lead to undefined behavior if myInt is actually a const member of Foo:
class Foo
{
int const myInt;
public:
const int& get() const
{
return myInt;
}
int& get()
{
return const_cast<int&>(static_cast<const Foo*>(this)->get());
}
};
int main()
{
Foo f;
f.get() = 10; // this compiles, but it is undefined behavior
}
The second version would not compile, because the non-const version of get would be ill-formed:
class Foo
{
int const myInt;
public:
int& get()
{
return myInt;
// this will not compile, you cannot return a const member
// from a non-const member function
}
const int& get() const
{
return const_cast<Foo*>(this)->get();
}
};
int main()
{
Foo f;
f.get() = 10; // get() is ill-formed, so this does not compile
}
This version is actually recommended by Scott Meyers in Effective C++ under Avoid Duplication in const and Non-const Member Function.
This is a follow-up to my previous question: C++ compile error constructing object with rvalue std::string from which I learned about the Most Vexing Parse.
I understand now the gist of the problem, however there's one leftover item of syntax I still don't quite understand, which I'd like to ask as a standalone question, since the discussions on the previous post were getting quite long.
Given this code:
#include <iostream>
#include <string>
class Foo
{
public:
Foo(double d)
: mD(d)
{
}
Foo(const std::string& str)
{
try
{
mD = std::stod(str);
}
catch (...)
{
throw;
}
}
Foo(const Foo& other)
: mD(other.mD)
{
}
virtual ~Foo() {}
protected:
double mD;
};
class Bar
{
public:
Bar(const Foo& a, const Foo& b)
: mA(a)
, mB(b)
{
}
virtual ~Bar() {}
protected:
Foo mA;
Foo mB;
};
int main(int argc, char* argv[])
{
if (argc < 3) { return 0; }
Foo a(std::string(argv[1]));
Foo b(std::string(argv[2]));
Bar wtf(a, b);
}
I understand, now, that the line Foo a(std::string(argv[1])); can be interpreted as either:
(1) Create a Foo named a with an anonymous std::string that is created with a char*. (My desired interpretation)
or
(2) A declaration (not definition) for a function named a that takes a std::string*.
From answers to the original question, I learned that functions could be declared within the scope of another function. That was new to me, but seems within reason, I can buy it.
What I can't wrap my head around, though, is the interpretation of std::string(argv[1]) as a std::string*.
argv[1] is a char*, so I still don't see why the line isn't interpreted as an anonymous std::string being constructed with a char*. After all, I've used code analogous to the following hundreds of times without ever scrutinizing whether this would result in anything other than the construction of a std::string with its char* constructor:
#include <iostream>
int main()
{
char* pFoo[] = {"foo"};
std::string str(pFoo[0]);
std::cout << str << std::endl;
return 0;
}
I'm on the cusp of understanding the most vexing parse problem; if someone could further explain this last niggling part, that might help push me over the edge.
Thank you.
Foo a(std::string(argv[1]));
declares a function named a which returns Foo and has one parameter (named argv) of type std::string[1]. Since array function parameters are always replaced with pointer parameters, the actual type of the function parameter becomes std::string*.
I ran into a strange issue.
Considering this example:
class Foo
{
static const int Bar = 5;
public:
Foo()
{
_map[Bar] = "some characters";
}
~Foo() {}
private:
std::map<int, std::string> _map;
};
int main()
{
Foo a;
return (0);
}
I get this error (compiling with g++ 4.7.2):
/tmp/ccLy806T.o: In function `Foo::Foo()':
Main.cpp:(.text._ZN3FooC2Ev[_ZN3FooC5Ev]+0x1e): undefined reference to `Foo::Bar'
Now, if I make a static_cast on Bar, it works:
Foo()
{
int i = Bar; //works
_map[static_cast<int>(Bar)] = "some characters"; //works
}
This error only appears when using Bar as map subscript in the constructor. Writing _map[Bar] = "some characters"; in an other function in the Foo class doesn't produce any error.
That's really strange for me, but I expect that someone here has an answer.
So, what am I doing wrong ?
That's because map::operator[] takes its key as a int const&. It wants the address of the thing you're passing into it. When you do:
_map[static_cast<int>(Bar)]
you're creating a temporary, and passing in the address to that temporary, which is fine. But when you're doing:
_map[Bar]
Bar doesn't actually have memory storage. You need to provide it via:
class Foo {
....
};
const int Foo::Bar;
You need to add the following at the top level to allocate storage for Foo::Bar:
const int Foo::Bar;
I have two classes, Foo and Bar. Bar maintains a reference to Foo, and has methods that call methods in Foo to change its state. The code is shown below.
class Foo
{
private:
double m_value;
public:
void setValue(double value) {
this->m_value = value;
};
double getValue() {
return this->m_value;
};
};
class Bar
{
private:
Foo& m_foo;
public:
Bar() : m_foo(Foo()) {
};
void setFooValue(double value) {
m_foo.setValue(value);
};
double getFooValue() {
return m_foo.getValue();
};
};
The problem arises when I try to access the value of foo after setting it, as below:
Bar bar;
bar.setFooValue(10000.0);
double value = bar.getFooValue();
std::cout << "Foo value is: " << value << std::endl;
Which outputs Foo value is -9.25596e+061. It appears the memory has become corrupt - why? I understand that not storing m_foo as a reference (i.e. using Foo m_foo;) will fix the issue, however I don't understand why this is either.
More puzzling still is that the code above works as desired when running in release mode.
I am using Visual Studio 2010 to compile.
Many thanks in advance!
Few compilers does report error for constructor Bar(). I have got the below error while compiling itself,
In constructor 'Bar::Bar()': invalid initialization of non-const
reference of type 'Foo&' from a temporary of type 'Foo' compilation
terminated due to -Wfatal-errors
Bar() : m_foo(Foo()) { };
In the constructor Bar, Foo() returns an object that is created in the stack and its life time ends when the constructor returns. Hence its life time is temporary and this will lead to accessing undefined memory or dangling references.
Solution 1: Use the Foo object as is without any reference
class Bar
{
private:
Foo m_foo;
public:
Bar(){
};
void setFooValue(double value) {
m_foo.setValue(value);
};
double getFooValue() {
return m_foo.getValue();
};
};
Solution 2: Pass Foo object as parameter to the Bar constructor and this will remain valid till the scope of main.
class Bar
{
private:
Foo &m_foo;
public:
Bar(Foo &x) : m_foo(x) {
};
void setFooValue(double value) {
m_foo.setValue(value);
};
double getFooValue() {
return m_foo.getValue();
};
};
int main()
{
Foo x;
Bar bar(x);
bar.setFooValue(10000.0);
double value = bar.getFooValue();
std::cout << "Foo value is: " << value << std::endl;
}
When you create Bar
Bar() : m_foo(Foo()) {
};
You provide reference to newly created foo instance that will go out of scope and will be deleted right after being assigned to m_foo. And this is actually VS c compiler flaw, since g++ would give you and error for such code, that you can see here.
http://liveworkspace.org/code/3kW04t$218
Bar() : m_foo(Foo())
You are trying to initialize lvalue-reference from temporary. You shouldn't do such things. After last bracket - object will be destroyed and you will have dangling reference.
Really, there is non-standard extension in MSVC, that allows bind temporary object to reference. For example gcc give error for such cases test here You can check this answer rvalue to lvalue conversion Visual Studio too.