This code can't pass compiling. The only difference is the return type. Foo1's return type is the user-defined struct and Foo2's is int.
struct test
{
};
test Foo1()
{
return test();
}
int Foo2()
{
return 0;
}
int main()
{
test& r1 = Foo1(); //ok
int& r2 = Foo2(); //no but why? Is it the C++ standard way?
return 0;
}
It is either a compiler bug or its "language extension" (for example MS VC++ has many such "language extensions"). In both cases of the function calls the compiler shall issue an error because it may not bind a temporary object to non-const reference.
If you want to have a reference you can still use a reference to const otherwise neither of the line will compile :
struct test
{
};
test Foo1()
{
return test();
}
int Foo2()
{
return 0;
}
int main()
{
const test& r1 = Foo1(); // ok now
const int& r2 = Foo2(); //ok now
return 0;
}
Related
If you have a class Base with virtual methods and a class Implementation which implements the virtual methods, is there any way to cast std::shared_ptr < Implementation > & to std::shared < Base > &? The compiler allows this for const references, but for non const references it fails as in "Case A" in the code below. Is there an easy way to do this?
If not, how safe is my workaround "questionable_cast" in Case B?
#include <iostream>
#include <memory>
class Base
{
public:
virtual void set_value(int x) = 0;
};
class Implementation : public Base
{
public:
Implementation() : m_value(0) { }
void set_value(int x) override
{
m_value = x;
}
int get_value() const
{
return m_value;
}
private:
int m_value;
};
void do_something(std::shared_ptr<Base>& base)
{
base->set_value(5);
/// Code like this makes the non-const argument necessary
base = std::make_shared<Implementation>();
}
template <class T, class U>
std::shared_ptr<T>& questionable_cast(std::shared_ptr<U>& u)
{
/// This code is here to assure the cast is allowed
std::shared_ptr<T> tmp = u;
(void)tmp;
return *reinterpret_cast<std::shared_ptr<T>*>(&u);
}
int main()
{
std::shared_ptr<Implementation> a = std::make_shared<Implementation>();
// The following line causes a compiler error:
// invalid initialization of reference of type ‘std::shared_ptr<Base>&’ ...
// do_something(a);
// do_something(std::dynamic_pointer_cast<Base>(a));
// This is the workaround
do_something(questionable_cast<Base>(a));
std::cerr << "a = " << a->get_value() << std::endl;
return 0;
}
Two obvious solutions to the problem as originally asked: 1. Make do_something take a const reference to a shared_ptr (or a shared_ptr by value). 2. Create a named shared_ptr and pass a reference to that: Eg
int main()
{
std::shared_ptr<Implementation> a = std::make_shared<Implementation>();
std::shared_ptr<Base> b = a; // This conversion works.
do_something(b); // Pass a reference to b instead.
return 0;
}
Your questionable_cast function is a violation of the strict aliasing rules, and invokes undefined behaviour. It's quite likely to work in initial tests, and then a new release of the compiler will crank up the optimization a notch, and it will fail during a demo.
To handle the case where do_something changes the pointer:
int main()
{
std::shared_ptr<Implementation> a = std::make_shared<Implementation>();
std::shared_ptr<Base> b = a; // This conversion works.
do_something(b); // Pass a reference to b instead.
const auto aa = std::dynamic_pointer_cast<Implementation>(b);
if (aa)
a = aa;
else
; // Handle the error here
return 0;
}
If do_something guarantees to return a pointer of the same derived type, even if it doesn't return the same pointer, wrap it in a template function:
template <typename T>
void do_something_ex( std::shared_ptr<T>& a )
{
std::shared_ptr<Base> b = a;
do_something(b)
a = std::dynamic_pointer_cast<T>(b);
if (!a)
throw_or_assert;
}
For defining a second const version of a function, is it guaranteed safe to do this? It looks like it would have infinite recursion as I want to return const but the other function which I mean to call is non-const.
It works with g++ but I worry that this is unsafe.
#include <iostream>
using namespace std;
class test {
public:
int* doSomething(int a) {
int* someInt = new int(a);
return someInt;
}
const int* doSomething(int a) const {
return doSomething(a);
}
};
int main() {
test a;
cout << *a.doSomething(12345) << endl;
return 1;
}
Not quite: as #Pete Becker has pointed out in the comments, if you had called the const version that will recurse:
class test {
public:
int* doSomething(int a) {
int* someInt = new int;
*someInt = a;
return someInt;
}
const int* doSomething(int a) const {
return doSomething(a);
}
};
int main() {
const test a;
// You're not in for a good time:
a.doSomething(12345);
return 1;
}
When providing const and non-const versions of a function that requires duplicated code, it's best to implement the const version, then have the non-const version call it in a specific way.
From Scott Myers Effective C++ - Third Edition:
When const and non-const member functions have essentially identical implementation, code duplication can be avoided by having the non-const version call the const version
Scott Myers goes on to provide a safe means for doing this:
const int* doSomething(int a) const
{
int* someInt = new int;
*someInt = a;
return someInt;
}
int* doSomething(int a)
{
return const_cast<int*>(static_cast<const Test&>(*this).doSomething());
}
In the non-const version, there are two casts: the static_cast basically turns this into const this, where the const_cast casts away the const-ness of the return. This is safe to do, because to call the non-const version, you must've had a non-const this.
However, if you are just providing access to a member, it's simple and easier to read to just have the following:
class TestAccess;
class Test
{
TestAccess& t;
public:
const TestAccess& getA() const { return t; }
TestAcess& getA() { return t; }
};
In this case the compiler is always going to pick the not const version of the function, is not even calling the const one.
Otherwise the compiler will not compile, you are braking the constenss.
For example I modified quickly the code:
#include <iostream>
using namespace std;
class test {
public:
int* doSomething(int a) {
int* someInt = new int;
*someInt = a;
return someInt;
}
int ax = 10;
void somethingElse(int i)
{
ax = i;
}
const int* doSomething(int a) const {
somethingElse(a);
return 0;
}
};
int main() {
test a;
cout << *a.doSomething(12345) << endl;
return 1;
}
This example does not compile because you are calling a const function inside a const scope. The compiler won't let you do that.
Now, I know is a test but doing this way you will never get out of the recursion, it will loop forever, and also you are leaking memory at every call by allocating on the heap, those two things together can lead to a disaster.
I cannot get a clear idea of whether this is legal, even after looking at related questions on SO and reading the C++03 standard page 192 (http://cs.nyu.edu/courses/fall11/CSCI-GA.2110-003/documents/c++2003std.pdf). Is this legal and safe:
const MyClass& f(const MyClass& arg) {
return arg;
}
void some_other_function() {
const MyClass& reference = f(MyClass());
// Use reference.
}
It seems to me that it is.
As far as I know, you can't do this. While binding a temporary to a const reference is legal C++(and lengthens the lifetime of that temporary -- see GOTW 88), further binding a const ref to another const ref doesn't lengthen the lifetime of that temporary.
The quote from page 192(C++03 standard):
A temporary bound to a reference parameter in a function call (5.2.2)
persists until the completion of the full expression containing the
call
I think the standard is pretty explicit that using reference after // Use reference. is invalid. I modified your snippet to check it(Mac OS X, clang: Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)):
#include <iostream>
struct MyClass
{
~MyClass()
{
std::cout << "~MyClass()" << std::endl;
}
};
const MyClass& f(const MyClass& arg) {
std::cout << "f()" << std::endl;
return arg;
}
int main() {
const MyClass& reference = f(MyClass());
std::cout << "main()" << std::endl;
}
It outputs:
f()
~MyClass()
main()
In other words, unless both me and clang developers are misinterpreting the C++ standard, it is illegal.
I was unable to get a clear interpretation from the standard, so I decided to check what's the de facto standard. The following code:
#include <cstdio>
struct MyClass
{
MyClass() { printf("constructor\n"); }
~MyClass() { printf("destructor\n"); }
MyClass(const MyClass&) { printf("copy\n"); }
MyClass(MyClass&&) { printf("move\n"); }
};
const MyClass& f(const MyClass& arg) {
return arg;
}
int main()
{
{
printf("before construction\n");
const MyClass& reference = f(MyClass());
printf("after construction\n");
}
printf("outside scope\n");
}
Yields:
before construction
constructor
destructor
after construction
outside scope
For MSVC, clang and g++. Seems it is not legal according to our main compiler suppliers.
This question is similar to following question: Pass const Key_Type& to operator[] of std::map
The code below explains what exactly is happening
#include <iostream>
struct MyClass{
int member;
MyClass():member(0){
std::cout<<"MyClass ctr "<<std::endl;
}
MyClass(const MyClass& rhs){
std::cout<<"MyClass copy ctr "<<std::endl;
}
~MyClass(){
std::cout<<"MyClass dtr"<<std::endl;
member = -1;
}
};
void f2(const MyClass& obj){
std::cout<<"func "<<obj.member<<std::endl;
}
const MyClass& f3(){
return MyClass();
}
MyClass f4(){
return MyClass(); //ideally not a good idea, exception is
//http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
}
int main()
{
std::cout << "-----Faulty Case-----------"<<std::endl;
//reference returned by f3 is local to f3 call and
//is destructed as soon as f3() is out of stack
//and hence the reference in f2() is not valid
f2( f3() );
std::cout <<std::endl<< "-----Correct way-----------"<<std::endl;
//A temporary object is returned by f4 which is then referred by reference in f2.
//This reference is alive in stack of f2 and hence can be used inside
//f2 with valid results.
//As explained in following article, the refernce should remain
//alive in stack to use temporary objects.
//http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
f2( f4() );
//note in previous expression, f4 returns by value but still copy ctr is not invoked,
//this I believe is Return Value Optimization (might be compiler dependent)
return 0;
}
Output of this program would be:
Executing the program....
$demo
-----Faulty Case-----------
MyClass ctr
MyClass dtr
func -1
-----Correct way-----------
MyClass ctr
func 0
MyClass dtr
Here is my code in C++:
MyClass foo1() {
return MyClass();
}
int MyClass::foo2() {
return 54;
}
And the question is, what is the value of:
foo1().foo2();
Is the value 54 or is it the MyClass object?
Since the dot . operator is evaluated left-to-right (i.e. first foo1() is called to determine the target of the invocation, and then its foo2() member is invoked), the answer is 54.
foo1().foo2(); means that foo1() returns an object or reference to an object that allows you to call foo2() on it.
Similar would be to store the return value of foo1() in a variable:
MyClass obj = foo1();
int ret = obj.foo2();
Example (lazy-loaded singleton):
class MyClass
{
public:
static MyClass& getInstance(){ static MyClass m; return m; }
int getNumber(){ return 54; }
};
int main()
{
std::cout << MyClass::getInstance().getNumber();
}
I am confused that why following code is not able to compile
int foo(const float* &a) {
return 0;
}
int main() {
float* a;
foo(a);
return 0;
}
Compiler give error as:
error: invalid initialization of reference of type 'const float*&' from expression of type 'float*'
but when I try to pass without by reference in foo, it is compiling fine.
I think it should show same behavior whether I pass by reference or not.
Thanks,
Because it isn't type-safe. Consider:
const float f = 2.0;
int foo(const float* &a) {
a = &f;
return 0;
}
int main() {
float* a;
foo(a);
*a = 7.0;
return 0;
}
Any non-const reference or pointer must necessarily be invariant in the pointed-to type, because a non-const pointer or reference supports reading (a covariant operation) and also writing (a contravariant operation).
const must be added from the greatest indirection level first. This would work:
int foo(float* const &a) {
return 0;
}
int main() {
float* a;
foo(a);
return 0;
}