Is this indirect const access an UB? - c++

When I was checking some code today, I noticed an old method for implementing std::enable_shared_from_this by keeping a std::weak_ptr to self in the constructor. Somthing like this:
struct X {
static auto create() {
auto ret = std::shared_ptr<X>(new X);
ret->m_weak = ret;
return ret;
}
// use m_weak.lock() to access the object
//...
private:
X() {}
std::weak_ptr<X> m_weak;
};
But then something came to me regarding constness of this object. Check the following code:
struct X {
static auto create() {
auto ret = std::shared_ptr<X>(new X);
ret->m_weak = ret;
return ret;
}
void indirectUpdate() const {
m_weak.lock()->val = 1;
}
void print() const {
std::cout << val << '\n';
}
private:
X() {}
std::weak_ptr<X> m_weak;
int val = 0;
};
int main() {
auto x = X::create();
x->print();
x->indirectUpdate();
x->print();
}
In this code, indirectUpdate() is a const method and it should not update our object, but in fact it does. Because std::weak_ptr.lock() returns a non-const shared_ptr<> even though the method is const. So you will be able to update your object indirectly in a const method. This will not happen in case of std::enable_shared_from_this because shared_from_this returns a shared pointer to const ref of object in const method. I wonder if this code is UB or not. I feel it should be, but I'm not sure. Any idea?
Update:
Sorry, it seems that my question was not relayed correctly. I meant even if we have a const pointer, we lose that constness via this method. following code shows that:
struct X {
static auto create() {
auto ret = std::shared_ptr<X>(new X);
ret->m_weak = ret;
return ret;
}
void show() const { std::cout << "const \n";}
void show() { std::cout << "non-const\n";}
void indirectUpdate() const {
show();
m_weak.lock()->show();
m_weak.lock()->val = 1;
}
void print() const {
std::cout << val << '\n';
}
int val = 0;
private:
X() {}
std::weak_ptr<X> m_weak;
};
int main() {
// Here we have a const pointer
std::shared_ptr<const X> x = X::create();
x->print();
x->indirectUpdate();
x->print();
}
and output will be following:
0
const
non-const
1
which shows losing constness.

The object that is modified is not const. There is no undefined behavior.
Add a method like this:
#include <memory>
#include <iostream>
struct X {
static auto create() {
auto ret = std::shared_ptr<X>(new X);
ret->m_weak = ret;
return ret;
}
void show() const { std::cout << "const \n";}
void show() { std::cout << "non-const\n";}
void indirectUpdate() const {
m_weak.lock()->show();
m_weak.lock()->val = 1;
}
void print() const {
std::cout << val << '\n';
}
private:
X() {}
std::weak_ptr<X> m_weak;
int val = 0;
};
int main() {
auto x = X::create();
x->print();
x->indirectUpdate();
x->print();
}
To get this output:
0
non-const
1
Modifying an object via a const mehtod is ok, as long as the method only modifies an object that is actually not const.
It is similar to using a const & to a non-const object. You may cast away constness and modify it as long as the object is really not const:
#include <iostream>
int main() {
int x = 0;
const int& ref = x;
const_cast<int&>(ref) = 42;
std::cout << x;
}
I also see no danger of misusing the pattern in your code, because once the object is const you won't be able to assign to its val member and all is fine with constcorrectness.
In your Update you have a const pointer in main but the object is still not const. Consider this simpler example:
#include <iostream>
struct foo {
static foo* create(){
auto x = new foo();
x->self = x;
return x;
}
void bar() const {
this->self->non_const();
}
void non_const() {
std::cout << "Hello World\n";
}
foo* self;
};
int main() {
const foo* f = foo::create();
f->bar();
delete f;
}
Its not quite the same as yours, but it has similar effect of calling a non-const method on a seemingly const object. Though its all fine.
The only foo object is that created in foo::create, it is not constant. In main we have a const foo* to that object. main can only call the const member bar. Inside bar the this pointer is a const foo*, but self does not point to a const foo. self itself is `const, but not the object it points to.

Related

What does const lambda mean?

#include <iostream>
int foo(int i)
{
const auto a = [&i](){ i = 7; return i * i; };
a();
return i;
}
int main()
{
std::cout << foo(42) << std::endl;
return 0;
}
This compiles( g++ -std=c++11 -Wall -Wextra -Wpedantic main.cpp ) and returns 49. Which is surprising to me, because by declaring a to be a constant object, I would have expected i to be referenced as const int&. It clearly isn't, why?
Lambdas are just like non-lambdas, except their implementation details are hidden. Therefore, it may be easier to explain using a non-lambda functor:
#include <iostream>
int foo(int i)
{
struct F {
int &i;
int operator()() const { i = 7; return i * i; }
};
const F a {i};
a();
return i;
}
int main()
{
std::cout << foo(42) << std::endl;
return 0;
}
F has a int & reference member i. const F cannot have its instance data modified, but a modification to i isn't a modification to its instance data. A modification to its instance data would be re-binding i to another object (which isn't allowed anyway).
[&i](){ i = 7; return i * i; }
is mainly equivalent to
class Lambda
{
public:
Lambda(int& arg_i) : i(arg_i) {}
auto operator() () const { i = 7; return i * i;}
private:
int& i;
};
And so then you have:
const Lambda a(i);
a();
And the const Lambda won't promote its member to const int& i; but int& const i; which is equivalent to int& i;.
When you capure i it is captured as the type it is.
So internally it has a int&. A const before the variable declaration of the closure does not change anything for the lambda.
You have 2 options to solve this:
const int i = 5;
auto b = [&i]() { i++; }; //error on i++
This way a const int& will be captured.
If you cannot change i for some reasons you can do this in c++14
int i = 5;
auto b = [i = static_cast<const int&>(i)]() { i++; }; //error on i++
This casts the int& to a const int& and will be stored as such in the lambda. Though this is way more verbose as you can see.
In the code you gave:
int foo(int i)
{
const auto a = [&i](){ i = 7; return i * i; };
a();
return i;
}
You are not assigning after you initialized your constant lambda function. Therefore, const doesn't mean much in this context.
What you have declared as const it isn't the context of your anonymous function or lambda exspression and its parameters, but only the reference at that lambda expression: const auto a.
Therefore, you cannot change the value of your lambda expr reference a because it is const, but its parameter passed by reference, &i, can be changed within the context of lambda expression.
If I understand correctly, the question is why you're allowed to mutate i even though a is const and presumably contains a reference to i as a member.
The answer is that it's for the same reason that you're allowed to do this on any object - assigning to i doesn't modify the lambda instance, it modifies an object it refers to.
Example:
class A
{
public:
A(int& y) : x(y) {}
void foo(int a) const { x = a; } // But it's const?!
private:
int& x;
};
int main()
{
int e = 0;
const A a(e);
a.foo(99);
std::cout << e << std::endl;
}
This compiles, and prints "99", because foo isn't modifying a member of a, it's modifying e.
(This is slightly confusing, but it helps to think about which objects are being modified and disregard how they're named.)
This "const, but not really" nature of const is a very common source of confusion and annoyance.
This is exactly how pointers behave, where it's more obviously not wrong:
class A
{
public:
A(int* y) : x(y) {}
void foo(int a) const { *x = a; } // Doesn't modify x, only *x (which isn't const).
private:
int* x;
};

Better way to initialize a "static const"-type variable member of a class in the main [duplicate]

This question already has answers here:
Can I initialize a static const member at run-time in C++?
(11 answers)
Closed 7 years ago.
I have a class that needs a static const variable member. The value for that class will be known at runtime by a user input. I have read a lot of post but so far none of the solution works. I am aware that this post:
Can I initialize a static const member at run-time in C++?
contains a work around, but it uses a global variable that I'd like to avoid. And also it doesn't really solve the problem.
Consider this:
#include
class A {
friend void foo(int);
static int dummy;
public:
static const int &T;
};
const int &A::T = A::dummy;
int A::dummy = 0;
void foo(int val) { A::dummy = val; }
int main() {
foo(10);
std::cout << A::T << std::endl;
foo(12);
std::cout << A::T << std::endl;
}
The program will compile and write 10 and 12 in the console. Wich defeats the purpose of the const qualifier. What is const here is the reference not the value. So I have come to the conclusion that it is not possible to have a static const class variable at execution time!
I know another way involving creating a setting-type class but it is not very neat.
So if someone knows a simple solution, please let us know!
If you don't like the global variables you could do the following scheme:
class A {
friend void foo(int);
static int dummy;
public:
static const int &T;
};
const int &A::T = A::dummy;
int A::dummy = 0;
void foo(int val) { A::dummy = val; }
int main() {
foo(10);
std::cout << A::T << std::endl;
}
Live Demo
That is declare a helper static int variable as private in your class. Make a friend a function that alters the value of that helper.
If you want to initialize it only once you can change the helper function to:
void foo(int val) {
static int count = 0;
if(!count) A::dummy = val;
++count;
}
Live Demo
Or if you don't like global functions you can make the foo function shown above a static member function of A as below:
class A {
static int dummy;
public:
static const int &T;
static void foo(int val) { A::dummy = val; }
};
const int &A::T = A::dummy;
int A::dummy = 0;
int main() {
A::foo(10);
std::cout << A::T << std::endl;
}
Live Demo
There is also something wrong with the solutions that I provided in the link of my original question and in the other solution I got. Consider this:
#include
class A {
friend void foo(int);
static int dummy;
public:
static const int &T;
};
const int &A::T = A::dummy;
int A::dummy = 0;
void foo(int val) { A::dummy = val; }
int main() {
foo(10);
std::cout << A::T << std::endl;
foo(12);
std::cout << A::T << std::endl;
}
The program will compile and write 10 and 12 in the console. Wich defeats the purpose of the const qualifier. What is const here is the reference not the value. So I have come to the conclusion that it is not possible the have a static const class variable at execution time!

C++ Force const-ness of lvalue in initializer expression

I would like the compiler to enforce const-ness of an lvalue (non-reference) but don't know if this is possible in C++. An example:
int foo() { return 5; }
int main() {
// Is there anything I can add to the declaration of foo()
// that would make the following cause a compile-error?
int a = foo();
// Whereas this compiles fine.
const int a = foo();
}
This is not really possible with something like an int because you need to give access to read the int and if they can read the int then they can copy it into a non-const int.
But from your comments it sounds like what you have in reality is not an int but a more complex user defined type, some sort of container perhaps. You can easily create an immutable container. This container could be a wrapper, or alternative implementation of your existing container. It then doesn't matter if the caller uses a const or non-const variable it is still immutable.
class MyClass {
std::vector<int> data;
public:
MyClass(size_t size) : data(size) {}
int& operator[](size_t index) { return data[index]; }
int operator[](size_t index) const { return data[index]; }
size_t size() const { return data.size(); }
};
class MyClassImmutable {
MyClass mc;
public:
MyClassImmutable(MyClass&& mc) : mc(std::move(mc)){}
int operator[](size_t index) const { return mc[index]; }
size_t size() const { return mc.size(); }
const MyClass& get() const { return mc; }
};
MyClassImmutable foo() {
MyClass mc(100);
mc[10] = 3;
return mc;
}
void func(const MyClass& mc);
int main() {
MyClassImmutable mci = foo();
std::cout << mci[10] << "\n"; // Can read individual values
//mci[10] = 4; // Error immutable
func(mc.get()); // call function taking a const MyClass&
}
Live demo.
Of course there is nothing to stop the caller from copying each and every value from your immutable container and inserting them into a mutable container.
Edit: An alternative approach might be to return a smart pointer-to-const. The only downside is you have to pay for a dynamic memory allocation:
std::unique_ptr<const MyClass> foo() {
auto mc = std::make_unique<MyClass>(100);
(*mc)[10] = 3;
return mc;
}
void func(const MyClass& mc);
int main() {
auto mc = foo();
std::cout << (*mc)[10] << "\n"; // Can read individual values
//(*mc)[10] = 4; // Error const
func(*mc); // can pass to a function taking a const MyClass&
}
It's not possible. foo() has no way of knowing about the type of the left hand side of the assignment, because when the assignment itself happens, foo() is already evaluated. The best you could hope for is to change the return value, to try and cause a type-based error on the initialization:
#include <type_traits>
struct my_int {
const int m;
template<typename T, typename std::enable_if<std::is_const<T>::value, T>::type* = nullptr>
constexpr operator T() const {return m;}
};
constexpr my_int foo() { return {5};}
int main() {
const int a = foo();
int b = foo();
}
Live example
But this will also not work, because the typename in the template will never be substitued by a const-qualified type (in this specific case, it will be int for both lines in main()).
As the following is possible
const int x = 4;
int y = x;
the C++ language will not provide such a mechanism.
Remains making a int const by a macro mechanism.
#define int_const_foo(var) const int var = ___foo()
int_const_foo(a);
Drawback: foo cannot be hidden, and the syntax is no longer C style.

default value of const reference parameter

Currently I have two functions:
void foo(const A & a) {
...
result = ...
result += handle(a); // 1
bar(result);
}
void foo() {
...
result = ...
bar(result);
}
All code in foo() are the same except 1.
Can I merge them to one function like following?
void foo(const A & a = 0) {
...
...
if (a) result += handle(a); // this won't work, but can I do something similar?
bar(result);
}
Btw, the parameter has to be a reference as I would like to keep the interface unchanged.
You can use the Null Object Pattern.
namespace
{
const A NULL_A; // (possibly "extern")
}
void foo(const A & a = NULL_A) {
...
result = ...
if (&a != &NULL_A) result += handle(a);
bar(result);
}
No. A reference is always an alias for a real object (assuming you don't trigger undefined behavior). You can achieve similar behavior without code duplication by accepting a pointer instead:
void foo_impl(A const* obj) {
// code as before, except access obj with -> rather than .
}
void foo (A const& obj) {
foo_impl(&obj);
}
void foo() {
foo_impl(nullptr);
}
In the spirit of DRY, why not merge them as such?
void foo(const A & a) {
foo();
handle(a);
}
void foo() {
...
...
}
The entire idea of using reference is that you avoid the NULL pointer issue. The reference nothing but an alias for the real object. I have an another simple idea for your program, basically you want to achieve two functionality with same function - using default parameters. Here is the code. Please excuse me for the variable names.
class ABC
{
public:
int t;
ABC operator=(ABC& other)
{
other.t = 0;
}
};
ABC other;
void foo( ABC &a=other);
void foo( ABC &a)
{
if( a.t == 0)
qDebug()<<"The A WAS ZERO";
else
qDebug()<<"THE A isn't zero";
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ABC hello;
hello.t = 100;
foo();
foo(hello);
return a.exec();
}
Here is the output.
The A WAS ZERO
THE A isn't zero
Use a base class that provides an interface, and two derived classes that implement the interface, one using A and the other using nothing.
Refactor foo to use a common foo.
struct Handler
{
virtual int get() = 0;
};
struct AHandler : Handler
{
AHandler(const A& a) : a_(a) {}
virtual int get() { return handle(a_); }
const A& a_;
}
struct NullHandler : Handler
{
virtual int get() { return 0; }
}
void foo(const Handler & h) {
...
result = ...
result += h.get();
bar(result);
}
void foo(const A & a) {
AHandler ah(a);
foo(ah);
}
void foo() {
NullHandler nh(a);
foo(nh);
}

How can I make this function act like an l-value?

Why can't I use the function ColPeekHeight() as an l-value?
class View
{
public:
int ColPeekHeight(){ return _colPeekFaceUpHeight; }
void ColPeekHeight( int i ) { _colPeekFaceUpHeight = i; }
private:
int _colPeekFaceUpHeight;
};
...
{
if( v.ColPeekHeight() > 0.04*_heightTable )
v.ColPeekHeight()-=peek;
}
The compiler complains at v.ColPeekHeight()-=peek. How can I make ColPeekHeight() an l-value?
Return the member variable by reference:
int& ColPeekHeight(){ return _colPeekFaceUpHeight; }
To make your class a good one, define a const version of the function:
const int& ColPeekHeight() const { return _colPeekFaceUpHeight; }
when I declare the function with the
two consts
When you want to pass an object into a function that you don't expect it to modify your object. Take this example:
struct myclass
{
int x;
int& return_x() { return x; }
const int& return_x() const { return x; }
};
void fun(const myclass& obj);
int main()
{
myclass o;
o.return_x() = 5;
fun(o);
}
void fun(const myclass& obj)
{
obj.return_x() = 5; // compile-error, a const object can't be modified
std::cout << obj.return_x(); // OK, No one is trying to modify obj
}
If you pass your objects to functions, then you might not want to change them actually all the time. So, to guard your self against this kind of change, you declare const version of your member functions. It doesn't have to be that every member function has two versions! It depends on the function it self, is it modifying function by nature :)
The first const says that the returned value is constant. The second const says that the member function return_x doesn't change the object(read only).
It can be rewritten like:
class View
{
public:
int GetColPeekHeight() const { return _colPeekFaceUpHeight; }
void SetColPeekHeight( int i ) { _colPeekFaceUpHeight = i; }
private:
int _colPeekFaceUpHeight;
};
...
{
cph = v.GetColPeekHeight();
if ( cph > 0.04 * _heightTable )
v.SetColPeekHeight( cph - peek );
}