D - 'dup cannot deduce function' when used inside 'const' property - d

Consider the following code:
class Bar
{
}
class Foo
{
private:
Bar[] bars_;
public:
Bar[] bars() const #property { return bars_.dup; }
}
void
main()
{
auto f = new Foo();
}
The intent is to have a read-only array of Bars. However this doesn't compile. Compilation fails with
template object.dup cannot deduce function
If const qualifier is removed, it compiles fine, but I really want to keep it - it does belong there. I've tried using bars_.dup!Bar instead, but that changes nothing. I'm clearly doing something wrong - DMD, LDC and GDC all display the same behaviour - but I can't figure out what.

You'd have to do some kind of deep copy there. With the const class, it means _bars is const too... which means the Bar is const as well. It is const all the way down.
The dup function only does a shallow copy. It copies the array with fresh references to the objects inside, but does not duplicate the objects themselves too. So the dup, while a fresh, mutable array, still points to the same const objects so it won't let you cast it to Bar[], only const(Bar)[].
The intent is to have a read-only array of Bars.
Here's how I'd do it:
const(Bar[]) bars() const #property { return bars_; }
Just return the existing reference without duplicating it, but mark it const on the return value.
The first const there with parens covers the return value, the next const covers the this reference. With both you should get what you want.

Related

Allowing a function to mutate a const object's member variable

This is related to the (currently) closed question I asked earlier: Can you mutate an object of custom type when it's declared as constant?
Suppose we have something that looks like the following:
class test
{
public:
test() : i{4}, ptr{&i} {};
int i;
int *ptr;
int *get_ptr() const {return ptr;}
};
void func(const test &t, int j) {
*(t.get_ptr()) = j;
// auto ptr = t.get_ptr();
// *ptr = j;
}
int main(int argc, char const *argv[])
{
test t;
std::cout << t.i << std::endl;
func(t, 5);
std::cout << t.i << std::endl;
}
We have this func that takes in a const test &. When I see this signature (and if I didn't look at the implementation of the function), it makes me want to assume that nothing in t will get modified; however, the member variable i is able to be modified through the ptr member variable, as we see here.
I don't usually write code that end up working this way, so I'm wondering if code like this is discouraged?
Furthermore, is it reasonable to assume (most of the time) that an object declared as const will not be mutated?
Yes code like this is definitely discouraged. It completely ignores the reason we have the const keyword in the first place. The function is deliberately modifying something that it is advertising it will not modify
That means that whoever wrote the get_ptr() function messed up because they declared it const but let it return a pointer to non-const object (so one that can be changed, defeating the purpose of declaring the function const)
If whatever get_ptr() returns could properly be modified by such a function then it should be an implementation detail, a private (or protected) variable marked with the mutable keyword.
test::get_ptr() should have two overloads.
const int* get_ptr() const { return ptr; }
int* get_ptr() { return ptr; }
If func() wants to change the test object given to it then it should take test&, not const test&
The key is here:
int *get_ptr() const {return ptr;}
You define get_ptr as const which is akin to saying "get_ptr is not going to change any attributes of the class". And it doesn't. It returns the value of the attribute ptr, which is a int*, and points to a mutable instance of an int which happens to be an attribute of the class as well.
The compiler has no way of knowing this, so from the compiler's perspective the promise was kept. However in reality you're circumventing the const qualifier and allowing to mutate an otherwise immutable attribute.
Not the best of coding practices, but whoever writes such code should, obviously, not expect for i to remain as it was set in the class methods if get_ptr is ever called.

Differentiating between const references to immutable vs. mutable objects

Is there any accepted way in C++ to differentiate between const references to immutable objects vs. mutable ones?
e.g.
class DataBuffer {
// ...
};
class Params {
// ...
};
class C {
public:
// Given references must be valid during instance lifetime.
C(const Params& immutableParameters, const DataBuffer& mutableDataBuffer) :
m_immutableParameters{immutableParameters},
m_mutableDataBuffer{mutableDataBuffer}
{
}
void processBuffer();
private:
const Params& m_immutableParameters;
const DataBuffer& m_mutableDataBuffer;
};
Here the semantic difference is given just in the names.
The problem is that const& instance variables only let you know the object won't be modified by the instance. There is no distinction in the interface whether or not they may be modified elsewhere, which I think is a useful feature to be able to describe in the interface.
Expressing this through the type-system would help make interfaces clearer, allow the compiler to catch errors (e.g. accidentally modifying parameters handed to a C instance, outside of the instance, in the example above), and possibly help with compiler optimizations.
Assuming that the answer is that the distinction isn't possible in C++, maybe there is something close which can be achieved with some templates magic?
Immutability is not part of the C++ type system. As such, you cannot differentiate between immutable objects and mutable ones. And even if you could, std::as_const will always ruin your attempt to do so.
If you are writing an interface that requires immutability of objects, the easiest way to handle this is to invoke the Fundamental Theorem of Software Engineering: "We can solve any problem by introducing an extra level of indirection." So make immutability part of the type system. For example (FYI: uses some small C++17 library stuff):
template<typename T>
class immutable
{
public:
template<typename ...Args>
immutable(std::in_place_t, Args &&...args) t(std::forward<Args>(args)...) {}
immutable() = default;
~immutable() = default;
immutable(const immutable &) = default;
//Not moveable.
immutable(immutable &&) = delete;
//Not assignable.
immutable operator=(const immutable &) = delete;
immutable operator=(immutable &&) = delete;
const T* operator->() const {return &t;}
const T& operator*() const {return t;}
private:
const T t;
};
With this type, the internal T will be immutable regardless of how the user declares their immutable<T>. Your C class should now take an immutable<Params> by const&. And since immutable<T> cannot be constructed from a copy or move of an existing T, the user is forced to use immutable<Params> whenever they want to pass that as a parameter.
Of course, your biggest danger is that they'll pass a temporary. But that was a problem you already needed to solve.
I don't know the reason, but here's how you can do it:
struct C {
template<typename T, typename T2>
C(T&&, const T2&&) = delete;
C(const Params&, const DataBuffer&) { /*...*/ }
};
By declaring a constructor that takes any argument by non-const reference, it will always be a better match than the constructor taking const&, as a cv-qualifier doesn't have to be added.
The const& constructor is a better match when passing a const parameters, as the cv-qualifier doesn't have to be removed.
DataBuffer db;
const Params cp;
C c{ cp, db }; // ok, second constructor call is chosen
Params p;
C c2{ p, db }; // error, constructor is deleted
Due note that, as #IgorTandetnik said, you can break your requirement easily:
Params pa;
const Params& ref_pa = pa;
C c3{ ref_pa, db }; // ok, but shouldn't compile.
As previous answers, C++ doesn't have the concept of "immutable". #Rakete1111 gave you the answer I would have used. However, Visual Studio will put global const variable in .rdata segment, where other variables will go to .data. The .rdata segment will generate a fault when trying to write.
If you need a run time test whether an object is read only, use a signal handler, like this:
#include <csignal>
const int l_ci = 42;
int l_i = 43;
class AV {};
void segv_handler(int signal) {
throw AV{};
}
template <typename T>
bool is_mutable(const T& t)
{
T* pt = const_cast<int*>(&t);
try {
*pt = T();
}
catch (AV av) {
return false;
}
return true;
}
void test_const()
{
auto prev_handler = std::signal(SIGSEGV, segv_handler);
is_mutable(l_i);
is_mutable(l_ci);
}
What you need is not a const reference, but a const object. Value semantics solve your problem. Nobody can modify a const object. While a reference is only const where it is marked const, because the referenced object may not be const. Take that for example :
int a;
int const& b = a;
// b = 4; <-- not compiling, the reference is const
Above, a is int, and b is a reference to const int. While a is not const, the language permit the reference to const to be bound on a non const object. So it's a reference to const object that is bound to a mutable object. The type system won't allow you to modify the mutable object through the reference, because it may have been bound to a const object. In our case it isn't, but the tribe don't change. However, even declaration of a reference to const won't change the original declaration. The int a is still a mutable object. a may still change value:
a = 7;
This is valid, whatever references or other kind of variables have been declared. A variable declared as int (no const) can change, and nothing can prevent it from changing. Heck, even another program like cheat engine can change the value of a mutable variable. Even if you had rules in the language to guarantee that it won't be modified, there is nothing they will prevent the mutable variable from changing values. In any language. In machine language, a mutable value is permitted to change. However, maybe some API of the operating system can help you change the mutability of memory regions.
What can you do to solve this problem now?
If you want to be 100% sure an object won't be modified, you must have immutable data. You usually declare immutable objects with the const keyword :
const int a = 8;
int const& b = a;
// a cannot change, and b is guaranteed to be equal to 8 at this point.
If you don't want a to be immutable and still guarantee b to not change, use values instead of references :
int a = 8;
const int b = a;
a = 9;
// The value of b is still 8, and is guaranteed to not change.
Here, value sematic can help you have what you want.
Then const reference are there for what? There are there to express what you are going to do with the reference, and help enforce what can change where.
As the question has been further clarified, no there is no way to determine if the reference has been bound to a mutable or immutable object in the first place. There is, however, some tricks you can have to differentiate the mutability.
You see, if you want more information about the mutability to be passed along with the instance, you can store that information in the type.
template<typename T, bool mut>
struct maybe_immutable : T {
using T::T;
static constexpr auto mutable = mut;
};
// v--- you must sync them --v
const maybe_immutable<int, false> obj;
This is the most simple way to implement it, but a naive one too. The contained data will be conditionally immutable, but it forces you to sync template parameter and constness. However, the solution allows you to do this :
template<typename T>
void do_something(const T& object) {
if(object.mutable) {
// initially mutable
} else {
// initially const
}
}
I hope I understand you question correct it is not as explicit as so to say "D language" but with const r-value references you can make immutable parameters.
What I understand from immutable is forexample
void foo ( const int&& immutableVar );
foo(4);-> is ok
int a = 5;
foo(a);->is not ok

const reference to a pointer can change the object

const references make sure you can't change the object you're referring to. For example:
int i = 1;
const int& ref = i;
ref = 42; // error, because of a const reference
But if you use a reference to a pointer or a unique_ptr, you can. Example:
class TinyClass {
public:
int var = 1;
void f1() { var = 42; }
};
std::unique_ptr<TinyClass> pointer(new TinyClass);
const std::unique_ptr<TinyClass>& constRef = pointer;
constRef->f1(); // no error
I assume this happens because the pointer itself wasn't changed. But this feels misleading, or like an easy mistake. Is there a simple way to declare a "real" const reference to a pointer? As in: makes sure the object itself is const.
edit: Assume that I can't just change the type of the unique_ptr. A real-world scenario would be that some objects are constructed in a vector<unique_ptr<C>> and some function gets a (const) reference to one of its elements.
The const in const std::unique_ptr<TinyClass>& constRef guarantees that constRef will not point to another object once it set up. It has nothing to do with the object itself.
If you want to prevent changing the object itself:
std::unique_ptr<const TinyClass> ptr_to_const_object;
Edit (after OP's edit):
You can not do anything. Since there is a function which wants const vector<unique_ptr<C>>&, the function clearly tells you that it needs to play with the object inside the pointer (and even the pointer) but it does not need to change the vector items (like adding new item or deleting it).

Returning "this" pointer in a const function

I've been learning C++ and I am practicing with classes at the moment.
I created a class that stores a name and a score of a player and defines functions to
manipulate the data and show it.
One of the functions I created is to compare scores of two players and return a pointer
to the player with the higher score. This is the function:
Player * Player::highestScore(Player p2)const
{
if(p2.pScore>pScore)
{
return &p2;
}
else
{
return this;
}
}
From the main I create the following players:
Player p1("James Gosling",11);
Player *p4 = new Player("Bjarne Stroustrup",5);
I call the highestScore function:
Player *highestScore = p1.highestScore(*p4);
However as you may have noticed from reading the function itself, when I return the pointer to the object that called the method (if it has a higher score), I get an error that says:
return value type does not match the function type
This problem seems to disappear when I declare the return type of the function as a const, like this:
const Player * Player::highestScore(Player p2)const
The part that is confusing me is why does it allow me to return &p2, which is not const and doesn't allow me to return this, which is a pointer to the object that called the function, which isn't a const as well? Also even when I declare the function return type as a const, it still allows me to return &p2, even though the argument passed to the parameter is not a const Player object?
Sorry if the question seems strange or what I'm trying to do is very bad programming, but it's just for the purpose of learning by doing it.
The part that is confusing me is why does it allow me to return &p2, which is not const and doesn't allow me to return this, which is a pointer to the object that called the function, which isn't a const as well?
this is const (or, more accurately, is a pointer-to-const) in a const member function, just like all the data members:
#include <iostream>
#include <type_traits>
struct A
{
void foo()
{
std::cout << std::is_same<decltype(this), const A*>::value << '\n';
}
void bar() const
{
std::cout << std::is_same<decltype(this), const A*>::value << '\n';
}
};
int main()
{
A a;
a.foo();
a.bar();
}
Output:
0
1
Also even when I declare the function return type as a const, it still allows me to return &p2, even though the argument passed to the parameter is not a const Player object?
We can't see what you tried, but presumably it was Player* const, which is not the same as Player const* (or const Player*). You can add constness to &r2 just fine; taking constness away is a different story.
The difference between a const and non-const method is that in the first the this pointer in const and in the latter it is not. So when you try to return non-const pointer from a const function and return this, compiler complains, because there this is const and const-ness can not be automatically removed.
&p2 is simply a pointer to an argument and thus it is not const. Please keep in mind, though that &p2 is pointer to local variable and it is never safe to return that.
When you have a "const" function, you are pretty much promising that "We will not change the object instance in this call". The compiler makes this a const T* this for that type of function (where T is the type of your class, e.g Player).
Obviously, returning a pointer to something that is const as as a non-const pointer is a breach of the rule - because once some code has a non-const pointer to your object, the code can modify the object... Which breaks the promise that "this function won't modify".
So adding const to the return type from function is the right solution here.
You probably also want to change your code so that it takes a const *Player p2 as input - your current code returns a pointer to a local variable [it happens to be an argument, but it's the same principle - it doesn't exist when the function call has returned].
Edit: Unless you are actually returning a copy of something (e.g. an integer, string or a new structure allocated with for example new) in a function with const attribute, the return type should be const.

Which are the implications of return a value as constant, reference and constant reference in C++?

I'm learning C++ and I'm still confused about this. What are the implications of return a value as constant, reference and constant reference in C++ ? For example:
const int exampleOne();
int& exampleTwo();
const int& exampleThree();
Here's the lowdown on all your cases:
• Return by reference: The function call can be used as the left hand side of an assignment. e.g. using operator overloading, if you have operator[] overloaded, you can say something like
a[i] = 7;
(when returning by reference you need to ensure that the object you return is available after the return: you should not return a reference to a local or a temporary)
• Return as constant value: Prevents the function from being used on the left side of an assignment expression. Consider the overloaded operator+. One could write something like:
a + b = c; // This isn't right
Having the return type of operator+ as "const SomeType" allows the return by value and at the same time prevents the expression from being used on the left side of an assignment.
Return as constant value also allows one to prevent typos like these:
if (someFunction() = 2)
when you meant
if (someFunction() == 2)
If someFunction() is declared as
const int someFunction()
then the if() typo above would be caught by the compiler.
• Return as constant reference: This function call cannot appear on the left hand side of an assignment, and you want to avoid making a copy (returning by value). E.g. let's say we have a class Student and we'd like to provide an accessor id() to get the ID of the student:
class Student
{
std::string id_;
public:
const std::string& id() const;
};
const std::string& Student::id()
{
return id_;
}
Consider the id() accessor. This should be declared const to guarantee that the id() member function will not modify the state of the object. Now, consider the return type. If the return type were string& then one could write something like:
Student s;
s.id() = "newId";
which isn't what we want.
We could have returned by value, but in this case returning by reference is more efficient. Making the return type a const string& additionally prevents the id from being modified.
The basic thing to understand is that returning by value will create a new copy of your object. Returning by reference will return a reference to an existing object. NOTE: Just like pointers, you CAN have dangling references. So, don't create an object in a function and return a reference to the object -- it will be destroyed when the function returns, and it will return a dangling reference.
Return by value:
When you have POD (Plain Old Data)
When you want to return a copy of an object
Return by reference:
When you have a performance reason to avoid a copy of the object you are returning, and you understand the lifetime of the object
When you must return a particular instance of an object, and you understand the lifetime of the object
Const / Constant references help you enforce the contracts of your code, and help your users' compilers find usage errors. They do not affect performance.
Returning a constant value isn't a very common idiom, since you're returning a new thing anyway that only the caller can have, so it's not common to have a case where they can't modify it. In your example, you don't know what they're going to do with it, so why should you stop them from modifying it?
Note that in C++ if you don't say that something is a reference or pointer, it's a value so you'll create a new copy of it rather than modifying the original object. This might not be totally obvious if you're coming from other languages that use references by default.
Returning a reference or const reference means that it's actually another object elsewhere, so any modifications to it will affect that other object. A common idiom there might be exposing a private member of a class.
const means that whatever it is can't be modified, so if you return a const reference you can't call any non-const methods on it or modify any data members.
Return by reference.
You can return a reference to some value, such as a class member. That way, you don't create copies. However, you shouldn't return references to values in a stack, as that results in undefined behaviour.
#include <iostream>
using namespace std;
class A{
private: int a;
public:
A(int num):a(num){}
//a to the power of 4.
int& operate(){
this->a*=this->a;
this->a*=this->a;
return this->a;
}
//return constant copy of a.
const int constA(){return this->a;}
//return copy of a.
int getA(){return this->a;}
};
int main(){
A obj(3);
cout <<"a "<<obj.getA()<<endl;
int& b=obj.operate(); //obj.operate() returns a reference!
cout<<"a^4 "<<obj.getA()<<endl;
b++;
cout<<"modified by b: "<<obj.getA()<<endl;
return 0;
}
b and obj.a "point" to the same value, so modifying b modifies the value of obj.a.
$./a.out
a 3
a^4 81
modified by b: 82
Return a const value.
On the other hand, returning a const value indicates that said value cannot be modified. It should be remarked that the returned value is a copy.:
For example,
constA()++;
would result in a compilation error, since the copy returned by constA() is constant. But this is just a copy, it doesn't imply that A::a is constant.
Return a const reference.
This is similiar to returning a const value, except that no copy is return, but a reference to the actual member. However, it cant be modified.
const int& refA(){return this->a;}
const int& b = obj.refA();
b++;
will result in a compilation error.
const int exampleOne();
Returns a const copy of some int. That is, you create a new int which may not be modified. This isn't really useful in most cases because you're creating a copy anyway, so you typically don't care if it gets modified. So why not just return a regular int?
It may make a difference for more complex types, where modifying them may have undesirable sideeffects though. (Conceptually, let's say a function returns an object representing a file handle. If that handle is const, the file is read-only, otherwise it can be modified. Then in some cases it makes sense for a function to return a const value. But in general, returning a const value is uncommon.
int& exampleTwo();
This one returns a reference to an int. This does not affect the lifetime of that value though, so this can lead to undefined behavior in a case such as this:
int& exampleTwo() {
int x = 42;
return x;
}
we're returning a reference to a value that no longer exists. The compiler may warn you about this, but it'll probably compile anyway. But it's meaningless and will cause funky crashes sooner or later. This is used often in other cases though. If the function had been a class member, it could return a reference to a member variable, whose lifetime would last until the object goes out of scope, which means function return value is still valid when the function returns.
const int& exampleThree();
Is mostly the same as above, returning a reference to some value without taking ownership of it or affecting its lifetime. The main difference is that now you're returning a reference to a const (immutable) object. Unlike the first case, this is more often useful, since we're no longer dealing with a copy that no one else knows about, and so modifications may be visible to other parts of the code. (you may have an object that's non-const where it's defined, and a function that allows other parts of the code to get access to it as const, by returning a const reference to it.
Your first case:
const int exampleOne();
With simple types like int, this is almost never what you want, because the const is pointless. Return by value implies a copy, and you can assign to a non-const object freely:
int a = exampleOne(); // perfectly valid.
When I see this, it's usually because whoever wrote the code was trying to be const-correct, which is laudable, but didn't quite understand the implications of what they were writing. However, there are cases with overloaded operators and custom types where it can make a difference.
Some compilers (newer GCCs, Metrowerks, etc) warn on behavior like this with simple types, so it should be avoided.
I think that your question is actually two questions:
What are the implications of returning a const.
What are the implications of returning a reference.
To give you a better answer, I will explain a little more about both concepts.
Regarding the const keyword
The const keyword means that the object cannot be modified through that variable, for instance:
MyObject *o1 = new MyObject;
const MyObject *o2 = o1;
o1->set(...); // Will work and will change the instance variables.
o2->set(...); // Won't compile.
Now, the const keyword can be used in three different contexts:
Assuring the caller of a method that you won't modify the object
For example:
void func(const MyObject &o);
void func(const MyObject *o);
In both cases, any modification made to the object will remain outside the function scope, that's why using the keyword const I assure the caller that I won't be modifying it's instance variables.
Assuring the compiler that a specific method do not mutate the object
If you have a class and some methods that "gets" or "obtains" information from the instance variables without modifying them, then I should be able to use them even if the const keyword is used. For example:
class MyObject
{
...
public:
void setValue(int);
int getValue() const; // The const at the end is the key
};
void funct(const MyObject &o)
{
int val = o.getValue(); // Will compile.
a.setValue(val); // Won't compile.
}
Finally, (your case) returning a const value
This means that the returned object cannot be modified or mutated directly. For example:
const MyObject func();
void func2()
{
int val = func()->getValue(); // Will compile.
func()->setValue(val); // Won't compile.
MyObject o1 = func(); // Won't compile.
MyObject o2 = const_cast<MyObject>(func()); // Will compile.
}
More information about the const keyword: C++ Faq Lite - Const Correctness
Regarding references
Returning or receiving a reference means that the object will not be duplicated. This means that any change made to the value itself will be reflected outside the function scope. For example:
void swap(int &x, int &y)
{
int z = x;
x = y;
y = z;
}
int a = 2; b = 3;
swap(a, b); // a IS THE SAME AS x inside the swap function
So, returning a reference value means that the value can be changed, for instance:
class Foo
{
public:
...
int &val() { return m_val; }
private:
int m_val;
};
Foo f;
f.val() = 4; // Will change m_val.
More information about references: C++ Faq Lite - Reference and value semantics
Now, answering your questions
const int exampleOne();
Means the object returned cannot change through the variable. It's more useful when returning objects.
int& exampleTwo();
Means the object returned is the same as the one inside the function and any change made to that object will be reflected inside the function.
const int& exampleThree();
Means the object returned is the same as the one inside the function and cannot be modified through that variable.
Never thought, that we can return a const value by reference and I don't see the value in doing so..
But, it makes sense if you try to pass a value to a function like this
void func(const int& a);
This has the advantage of telling the compiler to not make a copy of the variable a in memory (which is done when you pass an argument by value and not by reference). The const is here in order to avoid the variable a to be modified.