What's the difference between the types of bar1 and bar2?
int foo = 10;
auto bar1 = &foo;
auto *bar2 = &foo;
If both bar1 and bar2 are int*, does it makes sense to write the pointer declarator (*) in the bar2 declaration?
The declarations are exactly equivalent. auto works (almost) the same as template type deduction. Putting the star explicitly makes the code a bit easier to read, and makes the programmer aware that bar2 is a pointer.
Using auto * "documents intention". And auto *p = expr; can be deduced correctly only if expr returns pointer. Example:
int f();
auto q = f(); // OK
auto *p = f(); // error: unable to deduce 'auto*' from 'f()'
There is a big difference when you use const qualifiers:
int i;
// Const pointer to non-const int
const auto ip1 = &i; // int *const
++ip1; // error
*ip1 = 1; // OK
// Non-const pointer to const int
const auto* ip2 = &i; // int const*
++ip2; // OK
*ip2 = 1; // error
In this specific example both bar1 and bar2 are the same. It's a matter of personal preference though I'd say that bar2 is easier to read.
However, this does not hold true for references as seen in this example:
#include <iostream>
using namespace std;
int main() {
int k = 10;
int& foo = k;
auto bar = foo; //value of foo is copied and loses reference qualifier!
bar = 5; //foo / k won't be 5
cout << "bar : " << bar << " foo : " << foo << " k : " << k << endl;
auto& ref = foo;
ref = 5; // foo / k will be 5
cout << "bar : " << bar << " foo : " << foo << " k : " << k;
return 0;
}
As others said, they'll generate the same code. The asterisk is line noise (and makes it harder to switch from raw pointers to smart pointers if, for example, &foo is ever replaced by get_foo()). If you want to be explicit, then by all means, be explicit; but when you're using type inference, just let the compiler do its job. Lack of asterisks does not imply that an object isn't a pointer.
It doesn't matter as far as the interpretation of the C++ code goes; you can write whatever you want. However, there is a question of style and readability: Generally, you should not hide pointer, reference and CV qualifiers, and perhaps even smart pointers, in type aliases, since it makes it harder for the reader to understand that that's what's going on. Type aliases should package the semantically relevant type content, whereas qualifiers and modifiers should remain visible. So prefer the following:
using Foo = long_namespace::Foobrigation<other_namespace::Thing>;
using MyFn = const X * (int, int);
std::unique_ptr<Foo> MakeThatThing(MyFn & fn, int x) // or "MyFn * fn"
{
const auto * p = fn(x, -x);
return p ? p->Create() : nullptr;
}
And don't say:
using PFoo = std::unique_ptr<Foo>; // just spell it out
using MyFn = int(&)(int, int); // unnecessary; & is easy to spell
auto p = fn(x, -x); // Don't know that p is a pointer
Note also that reference qualifiers (unlike pointers) genuinely change the type of the variable that's being declared, so they're not optional:
X & f();
auto a = f(); // copy!
auto & b = f(); // b is the same as the return value of f()
Finally, adding explicit const pointer qualifications can help const-correctness. Consider the next example, in which a container contains pointers-to-mutable, but we only require const access. Just auto * would deduce a pointer to mutable, which we can avoid by saying const explicitly:
std::vector<X*> v = /* ... */;
for (const auto * p : v)
{
observe(p->foo()); // no need for a mutable *p
}
Related
I am rather confused with structural binding. Even if I use const and by-value (without &) structural binding as in this example:
#include <iostream>
#include <tuple>
int main()
{
int x = 0;
std::tuple<int&> p(x);
const auto [a] = p;
a++;
std::cout << x << '\n';
}
It still modifies x and prints 1: https://gcc.godbolt.org/z/jc8hxE8M6
Could you please explain why it works that way and want changes if I add & before [a] or remove const?
See the example on cppreference:
The portion of the declaration preceding [ applies to the hidden
variable e, not to the introduced identifiers.
int a = 1, b = 2;
const auto& [x, y] = std::tie(a, b); // x and y are of type int&
auto [z, w] = std::tie(a, b); // z and w are still of type int&
assert(&z == &a); // passes
Where e refers to
A structured binding declaration first introduces a uniquely-named variable (here denoted by e) to hold the value of the initializer, as follows: [...]
The const in your example does not apply to a, why it can still be useful is demonstrated by the next example:
int a = 1;
const auto& [x] = std::make_tuple(a); // OK, not dangling
auto& [y] = std::make_tuple(a); // error, cannot bind auto& to rvalue std::tuple
auto&& [z] = std::make_tuple(a); // also OK
The compiler deduces the type similar to the following
typedef int & Ref;
It is the element type of the std::tuple object.
If you will then write for example
int x = 0;
const Ref rx = x;
then the last declaration is equivalent to
int & const rx = x;
But opposite to pointers references may not be constant in this sense. So the qualifier const is just ignored and you have
int & rx = x;
Here is a demonstrative program.
#include <tuple>
#include <type_traits>
int main()
{
int x = 0;
std::tuple<int &> p( x );
const auto [a] = p;
std::cout << std::is_same_v<decltype( a ), int &> << '\n';
std::tuple<int *> p1( &x );
const auto [b] = p1;
std::cout << std::is_same_v<decltype( b ), int * const> << '\n';
}
The program output is
1
1
I was searching a bug in an application, which I've finally fixed but didn't understand completely.
The behavior can be reproduced with the following simple program:
#include <iostream>
#include <memory>
#include <functional>
struct Foo
{
virtual int operator()(void) { return 1; }
};
struct Bar : public Foo
{
virtual int operator()(void) override { return 2; }
};
int main()
{
std::shared_ptr<Foo> p = std::make_shared<Bar>();
std::cout << (*p)() << std::endl;
std::function<int(void)> f;
f = *p;
std::cout << f() << std::endl;
return 0;
}
The output of the line
std::cout << (*p)() << std::endl;
is 2, which is as I expected, of course.
But the output of the line
std::cout << f() << std::endl;
is 1. This was surprising me. I even was surprised that the assignment f = *p is allowed and doesn't cause an error.
I don't ask for a workaround, because I fixed it by a lambda.
My question is, what is happening when I do f = *p and why is the output 1 rather than 2?
I've reproduced the issue with gcc (MinGW) and Visual Studio 2019.
Further I want to mention that the output of
Bar b;
std::function<int(void)> f1 = b;
std::cout << f1() << std::endl;
is 2, again.
Object slicing happens here.
The point is given f = *p;, p is of type std::shared_ptr<Foo>, then the type of *p is Foo& (instead of Bar&). Even the assignment operator of std::function takes argument by reference, but
4) Sets the target of *this to the callable f, as if by executing function(std::forward<F>(f)).swap(*this);.
Note that the F above is deduced as Foo& too. And the constructor of std::function takes argument by value, object slicing happens, the effect becomes that f is assigned from an object of type Foo which is slice-copied from *p.
template< class F >
function( F f );
This is regular slicing, hidden under a layer of std::function and std::shared_ptr.
f = *p;
is valid because *p is a callable object with an appropriate operator(), and that is one of the things you can wrap in a std::function.
The reason that it doesn't work is that it copies *p – and that is a Foo&, not a Bar&.
This adaptation of your last example would behave the same:
Bar b;
Foo& c = b;
std::function<int(void)> f1 = c;
std::cout << f1() << std::endl;
Slicing
This is a case of slicing.
The reason is assignment operator of std::function (as demonstrated in another answer as well) which states:
Sets the target of *this to the callable f, as if by executing
function(std::forward(f)).swap(*this);. This operator does not
participate in overload resolution unless f is Callable for argument
types Args... and return type R. (since C++14)
https://en.cppreference.com/w/cpp/utility/functional/function/operator%3D
If you simplify and strip down the example - you can easily see what's going on:
Foo* p = new Bar;
Foo f;
f = *p;//<-- slicing here since you deref and then copy the object
It looks like you were aiming at obtaining a pointer to the overridden virtual function - unfortunately, theres no easy way to unroll the virtual function lookup as that is implemented via a runtime lookup table. However an easy workaround might be to use a lambda to wrap (As the OP also mentions):
f = [p]{return (*p)();};
A more suitable solution could also be to just a use reference_wrapper:
f = std::ref(p);
The static type of the pointer p is Foo.
So in this statement
f = *p;
there left operand *p has the type Foo that is there is slicing.
If a function takes a const & argument it should be immutable.
Why can I change values in a class passed as const?
How can I prevent a function taking const & to change values?
Note: compiles on vs2012 ad g++ 4.8.2
#include "iostream"
class Foo {
public:
Foo() : a(-99) {}
int a;
};
class Bar{
public:
Bar (Foo& f): rFoo(f), pFoo(&f), foo(f) {}
Foo& rFoo;
Foo* pFoo;
Foo foo;
};
void setA (const Bar & b){
Foo* f = new Foo();
Foo f2 = *f;
f->a = 7;
//b.foo.a = 8; // error C3490: 'a' cannot be modified because it is being accessed through a const object
//b.pFoo = f; // error C3490: 'pFoo' cannot be modified because it is being accessed through a const object
b.pFoo->a = 9; // OK... the pointer is const the location its pointing to not...
b.rFoo.a = 10; // Maybe ... the reference may be const, the location its is referencing not ...
b.rFoo = *f; // Why can I modify the reference ?
}
int main(int argc, char* argv[]){
Foo f;
Bar b(f);
std::cout << "one: " << b.rFoo.a << std::endl;
b.pFoo->a = 1;
b.foo.a = 2;
std::cout << "two: " << b.rFoo.a << std::endl;
setA(b);
std::cout << "three: " << b.rFoo.a << std::endl;
return 0;
}
Many Thanks in advance
You can modify the reference for the same reason you can modify the pointed to object by pFoo. Since you aren't modifying the objects member, but another referenced object.
b.rFoo = *f; // Foo's assignment operator invoked
That's why you should not expose members variables. Since you can't enforce a prevention to modify referenced objects, other than in your own member functions.
b.rFoo = *f
is not changing rFoo itself, it is equivalent to
b.rFoo.operator=(*f);
which copies *f to the object referenced by rFoo.
The const qualifier of an object indicates that the abstract state of this object won't change (i.e., from the client's point of view). This is not exactly the same as saying that the object's raw bits are not going to change.
It is forbitten to C++ compilers to consider objects as raw bits, unless they can resolve the problem of aliasing. which in your case the compiler cannot. This is due to the fact that Foo* pFoo is a pointer to an object and consequently the state of this object is modifiable. That is, even if the object that pFoo points to changes, the object that contains pFoo (i.e., b) doesn't change since pFoo continues to point to the same object.
C++
I want to know if a pointer that isn’t already a two-const pointer (e.g. T const * const) can be implicitly or explicitly cast, processed through something (e.g. a function), or otherwise converted, to yield a T const * const, without or before being used to initialize a variable that is declared as a T const * const. How can I do this?
I thought that if I started with a T*, then one const_cast (or two, in case the cast can only cast in one const at a time) would suffice, but apparently it doesn’t. Many variables in the code show a different unsuccessful attempt at yielding T const * const through casting or returning from a function. Every cast failed to return a pointer with a trailing const. (I refer to the const to the left of * as the leading const and the one to the right of * as the trailing const.) Because of the unsuccessful casts, I tried unsuccessfully to force the const through direct initialization. This was compiled in VC11. g++ on stack-crooked.com gives a logically equivalent console output, albeit with different names for typeid(/*...*/).name().
#include <iostream>
#include <typeinfo>
using namespace std;
int const * const foo()
{
return nullptr;
}
int main()
{
int x = 7;
auto a1 = &x;
cout << typeid(a1).name() << endl;
auto a2 = const_cast<int const *>(&x);
cout << typeid(a2).name() << endl;
auto a3 = const_cast<int * const>(&x);
cout << typeid(a3).name() << endl;
auto a4 = const_cast<int const * const>(&x);
cout << typeid(a4).name() << endl;
auto a5 = const_cast<int const * const>(a4);
cout << typeid(a5).name() << endl;
auto a6 = (int const * const) &x;
cout << typeid(a6).name() << endl;
auto a7 = static_cast<int const * const>(a4);
cout << typeid(a7).name() << endl;
auto a8 = reinterpret_cast<int const * const>(a4);
cout << typeid(a8).name() << endl;
auto a9 = foo();
cout << typeid(a9).name() << endl;
int const * const a10 = &x;
cout << typeid(a10).name() << endl;
cout << ( typeid(a10) == typeid(a4) ) << endl;
auto a12 = a10;
cout << typeid(a12).name() << endl;
cout << ( typeid(a12) == typeid(a4) ) << endl;
}
Expected results vs. actual results, and questions:
Question numbers correspond to the same-numbered a# variables.
Got expected result int *
Got expected result int const *
Expected int* const, but got int*. Did the const_cast ignore its trailing const argument and why? Since the return is the same constness and type as the argument, did the cast run at all?
Expected int const * const, but got int const*. Did the const_cast ignore its trailing const argument and why?
I wanted to see if const_cast<int const * const> will include a trailing const in the result given that the argument a4 already has a leading const. Expected int const * const. Got int const*. Did the const_cast ignore its trailing const argument and why?
Expected int const * const. Got int const*. Why would the explicit cast still exclude the trailing const?
Expected int const * const. Got int const*. Why would the static_cast exclude the trailing const?
Expected int const * const. Got int const*. Why would the reinterpret_cast exclude the trailing const?
Expected int const * const. Got int const*. Why would an initialization to the int const * const return of a function still exclude the trailing const in the result?
Expected int const * const. Got int const* from the console output but not from the debugger. a10 is explicitly declared as int const * const, so why does the typeid().name() exclude the trailing const? operator== yields 1, so why is the typeid() itself (not just the name) for a10 equivalent to that of a4? The VC11 debugger lists a10’s type as int const * const. Why is it different than the one from typeid() and typeid().name()? Which one is correct?
variable name a11 omitted because it looks like the word “all”.
I expected a12 to be int const * const because it is initialized to a10, which was explicitly declared int const * const. operator== yields 1, so typeid() is still int const*. Got int const* from both the console output and the debugger. Why are they different from the expected result?
Are all casts, function returns, and initializations limited to only casting in one const at a time? Is the leading const the only thing they can cast in?
const_cast does work the way you think it does. However, auto doesn't do what you think it does. auto works similarly to function template parameter deduction (in fact, it's defined in terms of the latter). Now consider:
template<typename T>
void f(T x);
f(42);
int const n = 42;
f(n);
Both calls are to f<int>(), not f<const int>(). Top-level const modifiers are ignored by template parameter deduction. For the same reason, in this example
auto a = 42; a = 84;
auto b = n; b = 84;
variables a and b are of type int, not const int, and can be modified.
I'm pretty new to C++ and as an exercise (and perhaps eventually .Net utility) I'm doing a pointer wrapper (actually in C++/CLI, but this applies to C++ as well). This pointer wrapper (called Apont) currently behaves just like a pointer would, as the test below can show, if lines marked 1. and 2. are commented out:
int main(array<System::String ^> ^args)
{
double ia = 10; double ip = 10;
double *p = &ip; // pointer analogy
Apont<double> ^a =
gcnew Apont<double>(ia); // equivalent to what's below, without errors
a = ~ia;/* 1. IntelliSense: expression must have integral or unscoped enum type
error C2440: '=' : cannot convert from 'double' to 'Utilidades::ComNativos::Apont<T> ^'
error C2171: '~' : illegal on operands of type 'double'*/
Console::WriteLine("ip = {0}; *p = {1}; ia = {2}; !a = {3}", ip, *p, ia, !a);
ia = 20; ip = 20;
Console::WriteLine("ip = {0}; *p = {1}; ia = {2}; !a = {3}", ip, *p, ia, !a);
*p = 30; // pointer analogy
a->Valor = 30; // does exacly what's below, without errors
!a = 30;/* 2. IntelliSense: expression must be a modifiable lvalue
error C2106: '=' : left operand must be l-value */
Console::WriteLine("ip = {0}; *p = {1}; ia = {2}; !a = {3}", ip, *p, ia, !a);
//a->Dispose();
Console::ReadKey();
p = nullptr;
return 0;
}
There are two things I don't like here, marked with 1. and 2. in the code comments, before the lines with errors. The operator~ (see 1.) is defined outside Apont, below:
template<typename T> static Apont<T>^% operator ~(T& valor)
{
return gcnew Apont<T>(valor);
}
I think this one has to be defined outside Apont, but I'm not sure. I cannot understand very well the errors it produces (these are, of course, in the use, not in the definition).
To set the value to which the instance of Apont refers I must use a property (the line marked 2. doesn't work, with errors in the setting usage only), Apont::Valor, which is the equivalent to use *p. What I'd like to do is as I use *p to get or set the value it points to, use !a with the same effect on Apont. Here's Apont::operator!()'s current definition:
T operator !()
{
return Valor;
}
As you can see in 2. (comment in the code, before the respective errors), it doesn't work for setting a value. Maybe I should return a reference? Make another operator with the same name, perhaps outside the class? I tried several options, however, I got similar errors, and came out more confused.
The question is: how can I make an operator that behaves like & (in this case, ~) and one that behaves like * (in this case, !, for dereference, but that behaves like Apont::Valor, whose old definition you can see below)?
property T Valor
{
T get()
{
if (pointer != nullptr)
return *pointer;
else if (eliminado && ErroSeEliminado) // means "disposed && ErrorIfDisposed"
throw gcnew ObjectDisposedException("O objeto já foi pelo menos parcialmente eliminadao.");
else if (ErroSeNulo) // means "ErrorIfNull"
throw gcnew NullReferenceException();
else
return 0;
// don't worry, this is not default behavior, it is returned only if you want to ignore all errors and if the pointer is null
}
void set(T valor)
{
*pointer = valor;
}
}
Let me recap in a new answer for clarity.
Solving the ! operator is easy, as I said in my previous answer, just add a reference.
So for the operator ~, the goal was to have it behave like the & operator and call the constructor of the pointer wrapper class.
I don't think that is possible. It is certainly possible for user defined objects, but I don't think it is possible to overload unary operators for builtin types. So there are three solutions depending on what you prefer:
The first one does exactly what you want, but will break for primitive types:
#include <iostream>
template<typename T>
struct A {
T* payload;
A()
: payload(NULL){}
A(T *ptr)
: payload(ptr) {}
T& operator !(){
return *payload;
}
};
// this will not work for primary types
template<typename T>
A<T> operator ~(T &b){
return A<T>(&b);
}
struct B{
int test;
};
int main(){
B b; b.test = 4;
A<B> a;
a = ~b; // I think this is what you want
std::cerr << (!a).test << std::endl;
// this does not work
//int i = 4;
//A<int> a;
//a = ~i;
}
Second solution: use a compound assignment operator. Pros are the side effects are minimal, cons is this is not very intuitive and might break the nice design you had in mind.
#include <iostream>
template<typename T>
struct A {
T* payload;
A() : payload(NULL){}
T& operator !(){
return *payload;
}
};
template<typename T>
A<T>& operator &=(A<T> &a, T& b){ // should be friend of the above
a.payload = &b;
return a;
}
int main(){
int i = 3;
A<int> a;
a &= i;
std::cerr << !a << std::endl;
}
Third solution: overload the basic assignment operator. This is more intuitive to write but has a lot of side effects:
#include <iostream>
template<typename T>
struct A {
T* payload;
A() : payload(NULL){}
T& operator !(){
return *payload;
}
A<T>& operator = (T & b) {
payload = &b;
return *this;
}
};
int main(){
int i = 3;
A<int> a;
a = i;
std::cerr << !a << std::endl;
}
Someone might have a solution to hijack the operators for primitive types, but i can't think of any simple solution.
If i understood your code correctly, you want the operator ~ to return a copy of the pointer wrapper and the operator ! to act as dereference?
In this case, you can define the unary operator ~ inside the Apont class which calls a copy constructor. And the operator ! has to return a reference indeed if you want to asign a value.
I think the following c++ code defines what you want to do (I renamed Apont to A):
#include <iostream>
template<typename T>
struct A {
T* payload;
A(T *ptr)
:payload(ptr) {}
A(const A&other)
:payload(other.payload) {}
T& operator !(){
return *payload;
}
T* operator ~(){
return payload;
}
};
int main(){
#define PRINT(X) std::cerr << #X << " = " << X << std::endl
int i = 0;
PRINT(i);
A<int> a(&i);
!a = 1;
PRINT(i);
A<int> b = ~a;
!b = 2;
PRINT(i);
}
The output of the code above is:
i = 0
i = 1
i = 2
According to your comments, you said you wanted the operator ! to behave exactly like the wrapped pointer. You can do so, but then the syntax changes and you need to dereference it to assign a new value (because it is a pointer...). ie something like:
#include <iostream>
template<typename T>
struct A {
T* payload;
A(T *ptr): payload(ptr) {}
// this now behaves like accessing the wrapped pointer directly
T*& operator !(){
return payload;
}
};
int main(){
#define PRINT(X) std::cerr << #X << " = " << X << std::endl
int i = 0;
int j = 999;
PRINT(i);
A<int> a(&i);
*(!a) = 1; // note the change of syntax here
PRINT(*!a); // and here
!a = &j; // but now you can change the wrapped pointer through the operator
PRINT(*!a);
}