This code below will result in memory loss because rA is initialized as invalid when it is constructed. When can I do to fix this problem?
Use shared_ptr or hope for future compiler versions to catch this bad code?
#include <memory>
using namespace std;
struct A {};
void use(const A& a) {};
unique_ptr<A> foo()
{
unique_ptr<A> pa(new A());
return pa;
}
int main()
{
const A& rA = *foo(); // rA is unusable, initialized with invalid reference (invalidated by destruction of temporary unique_ptr returned from foo)
use(rA);
}
Rewrite your main as:
int main()
{
auto a = foo();
use(*a);
}
As an aside I would rewrite foo as:
std::unique_ptr<A> foo()
{
return std::make_unique<A>();
}
When you return objects by value you return a temporary that will get destroyed immediately unless it is copied or bound to a variable from the caller's side.
What you are doing wrong is binding a reference to something the returned temporary object contains and not the returned object itself. By the time you access the thing you have bound a reference to it has been deleted by the temporary object's destructor when it was destroyed.
To illustrate what you are doing wrong I have written an equivalent example using a std::vector and binding a reference to one of its elements:
void use(const int& a) {}
std::vector<int> foo()
{
return {1, 2, 3};
}
int main()
{
const int& rA = foo()[0]; // bind to an element
// the vector itself is destroyed by the time we get here
use(rA); // whoops using a reference to an element from a destroyed vector
}
Related
int& getRef() {
int* ptr = new int;
*ptr = 42;
return *ptr;
}
int main()
{
int& ref = getRef();
std::cout << ref;
}
Is ref here a dangling reference after the call to getRef()?
This is how I typically reason about dangling references:
A reference is an alias to an object
If the object is destroyed, then the reference becomes a dangling reference.
However, in this case, it's not clear to me which object is the reference an alias to? And without knowing what the object is, I can't figure out whether that object is destroyed or not :).
Similar to the above, how about this piece of code?
int& getRef(std::shared_ptr<int> sharedPtr) {
return *sharedPtr;
}
int main()
{
auto sharedIntPtr = std::make_shared<int>(42);
int& ref = getRef(sharedIntPtr);
std::cout << ref;
}
Is ref here a dangling reference after the call to getRef()?
No. It references the object you created with new that has not been destroyed.
it's not clear to me which object is the reference an alias to? And without knowing what the object is, I can't figure out whether that object is destroyed or not
It's not destroyed so your program leaks. To destroy the object, you could end your program with:
delete &ref;
In you your second example you are referencing the int managed by the two shared_ptrs and there will be no leaks since the last shared_ptr that goes out of scope destroys the int.
A reference is not exactly an alias, it is a different variable that points to the same address that you initialized it with during all its lifetime.
If you want to know if a object is being destroyed or not in some conditions, you can take advantage of destructors.
#include <iostream>
class myClass
{
private:
int x;
public:
myClass(int _x): x(_x) {}
int getX() const {return x;}
~myClass(){std::cout << "Object distroyed! Value: " << x << std::endl;}
};
myClass& getRef() {
myClass* ptr = new myClass(42);
return *ptr;
}
int main()
{
myClass& ref = getRef();
std::cout << ref.getX() << std::endl;
}
Here we can see that the destructor never runs and therefore the object is not being destroyed. That is because you allocated it in the heap and it will not be destroyed unless you use delete &ref;.
I am exploring the use of std::function and std::bind. I see that you can bind a member function, for example:
class A{
int c_ = 10;
public:
int add(int a, int b){
return a + b + c_;
}
};
int main(){
A* p_a = new A;
std::function<int()> f = std::bind(&A::add, p_a, 1, 1);
printf("%i\n", f()); // yields "12" (1 + 1 + 10)
delete p_a;
printf("%i\n", f()); // yields derpy numbers, no errors thrown.
}
Is there a way to detect if p_a has been deleted?
My solution to do this is having a wrapper class that holds the function and a weak_ptr to the object. I am just wondering if there is a more elegant way to do this.
std::bind can accept smart pointers, so you can simply pass std::shared_ptr<A> to it.
std::shared_ptr<A> p_a(new A);
std::function<int()> f = std::bind(&A::add, p_a, 1, 1);
Note, that the functor will own the object: the object will live as long as the functor lives. If you don't want such behavior, then your solution with a weak_ptr wrapper is nice.
struct A{
int c_ = 10;
int add(int a, int b){
return a + b + c_;
}
};
template<class T>
std::weak_ptr<T> weak( std::shared_ptr<T> const& sp ) { return {sp}; }
int main(){
auto p_a = std::make_shared<A>();
std::function<int()> f = [w_a = weak(p_a)]() {
if (auto p_a = w_a.lock())
return p_a->add(1,1);
throw w_a;
}
printf("%i\n", f()); // yields "12" (1 + 1 + 10)
p_a.reset();
try {
printf("%i\n", f()); // yields derpy numbers, no errors thrown.
} catch( std::weak_ptr<A> wp ) {
printf("object deleted\n");
}
}
live example.
in general, in C++ you don't pay for what you don't use.
Tracking the lifetime of objects has a cost. If you want to track the lifetime of objects, you can use a shared_ptr or weak_ptr to the (free-store) allocated object, or use a weak_ptr to a shared_ptr (uniquely) owned by the object to indicate its lifetime is over.
The above is an implementation using C++14 lambdas to capture the object's shared pointer as a weak ptr, and give defined behavior (a throw of a copy of said weak pointer) if it has been deleted.
A lifetime token looks like:
using lifetime_token = std::weak_ptr<void>;
struct has_lifetime {
has_lifetime():token(std::make_shared<char>()) {}
has_lifetime(has_lifetime const&o):has_lifetime() {} // not default
lifetime_token get_lifetime() const {
return token;
}
private:
std::shared_ptr<void> token;
};
inheriting from has_lifetime gives you a get_lifetime() member that exists for as long as you do (it is destroyed by your destructor, and can no longer be .lock()d).
This is an easier pattern to follow if you cannot modify the ownership semantics of the original class. Simply .lock() the lifetime_token of the object to determine if it is still alive.
If i have an instance of std::function that is bound to a member function of an object instance and that object instance goes out of scope and is otherwise destroyed will my std::function object now be considered to be a bad pointer that will fail if called?
Example:
int main(int argc,const char* argv){
type* instance = new type();
std::function<foo(bar)> func = std::bind(type::func,instance);
delete instance;
func(0);//is this an invalid call
}
Is there something in the standard that specifies what should happen? My hunch is that it will throw and exception because the object no longer exists
EDIT:
Does the standard specify what should happen?
Is it undefined behavior?
EDIT 2:
#include <iostream>
#include <functional>
class foo{
public:
void bar(int i){
std::cout<<i<<std::endl;
}
};
int main(int argc, const char * argv[]) {
foo* bar = new foo();
std::function<void(int)> f = std::bind(&foo::bar, bar,std::placeholders::_1);
delete bar;
f(0);//calling the dead objects function? Shouldn't this throw an exception?
return 0;
}
Running this code i receive an output value of 0;
What will happen is undefined behavior.
The bind() call will return some object that contains a copy of instance, so that when you call func(0) will effectively call:
(instance->*(&type::func))(0);
Dereferencing an invalid pointer, as you would do there if instance were deleted, is undefined behavior. It will not throw an exception (although, it's undefined, so it could, who knows).
Note that you're missing a placeholder in your call:
std::function<foo(bar)> func =
std::bind(type::func, instance, std::placeholders::_1);
// ^^^^^^^ here ^^^^^^^^^
Without that, you can't call func(0) even with a non-deleted instance.
Updating your example code to better illustrate what's going on:
struct foo{
int f;
~foo() { f = 0; }
void bar(int i) {
std::cout << i+f << std::endl;
}
};
With that added destructor, you can see the difference between copying the pointer (in f) and copying the object that was pointed to (in g):
foo* bar = new foo{42};
std::function<void(int)> f = std::bind(&foo::bar, bar, std::placeholders::_1);
std::function<void(int)> g = std::bind(&foo::bar, *bar, std::placeholders::_1);
f(100); // prints 142
g(100); // prints 142
delete bar;
f(100); // prints 100
g(100); // prints 142 still, because it has a copy of
// the object bar pointed to, rather than a copy
// of the pointer
According to §7.1.5.1/4:
Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior.
So my question becomes: when is an object a const object?
In particular, is a const member in a non-const object considered a const object?
class Foo {
const Bar bar;
void replaceBar(Bar bar2) {
*(const_cast<Bar *>&bar) = bar2; // Undefined behavior?
}
}
This comes up because I have an immutable class (all fields are const), but I want to have a move constructor, which technically modifies the value passed in. I'm ok with "cheating" in that case, since it doesn't break logical constness.
The simple rule is: it is ok to cast away constness if the original object is not const. So if you have a non-cont object and, say, you pass the const reference to it to a function, it is legal to cast away constness in the function.
In your example the original object is const, so casting constness away is undefined behaviour.
Let us make this a full example:
struct Bar { int x; };
struct Foo {
const Bar bar;
Foo( int x ):bar(x) {}
void replaceBar(Bar bar2) {
*(const_cast<Bar *>&bar) = bar2; // Undefined behavior?
}
};
now, let us break the world.
int main() {
Foo f(3);
Bar b = {2};
f.replaceBar(b);
std::cout << f.bar.x << "\n";
}
the above can and probably should output 3, because a const object Bar was created with x=3. The compiler can, and should, assume that the const object will be unchanged throughout its lifetime.
Let's break the world more:
struct Bar {
int* x;
Bar(int * p):x(p) {}
~Bar(){ if (x) delete x; }
Bar(Bar&& o):x(o.x){o.x=nullptr;}
Bar& operator=(Bar&& o){
if (x) delete x;
x = o.x;
o.x = nullptr;
}
Bar(Bar const&)=delete;
Bar& operator=(Bar const&)=delete;
};
struct Foo {
const Bar bar;
Foo( int* x ):bar(x) {}
void replaceBar(Bar bar2) {
*(const_cast<Bar *>&bar) = bar2; // Undefined behavior?
}
};
now the same game can result in the compiler deleting something twice.
int main() {
int* p1 = new int(3);
Foo f( p1 );
Bar b( new int(2) );
f.replaceBar(std::move(b));
}
and the compiler will delete p1 once within replaceBar, and should delete it also at the end of main. It can do this, because you guaranteed that f.bar.x would remain unchanged (const) until the end of its scope, then you violated that promise in replaceBar.
Now, this is just things the compiler has reason to do: the compiler can literally do anything once you have modified an object that was declared const, as you have invoked undefined behavior. Nasal demons, time travel -- anything is up for grabs.
Compilers use the fact that some behavior is undefined (aka, not allowed) to optimize.
We know that we can pass temporary objects to functions by const reference, like this:
class A
{
public:
A(int _b = 0)
{
b = _b;
}
int b;
};
void foo(A& a) {printf("%d", a.b);}
void cfoo(const A& a) {printf("%d", a.b);}
int main(void)
{
//foo(A(4)); doesn't compile
cfoo(A(5));
}
but what about passing by pointer?
why does this compile?
void pfoo(A* pa) {pa->b = 19;}
int main(void)
{
pfoo(&A(5));
}
but what about passing anonymous variables pointer? why does this compile?
You are probably using a compiler that does not honour C++ standard.
No address of an r-value (temporary) object can be taken. That should not compile.
However, operator& can be overloaded, so that it can be invoked on a temporary object, e.g.:
struct A
{
A* operator&() { return this; }
};
In C++11 a temporary object can be bound to an r-value reference. After that r-value reference behaves like an l-value and hence the address of a temporary object can be taken:
struct A {};
void foo(A*);
void foo(A&& a) { foo(&a); }
int main() {
foo(A{});
}