foo.h
#include <iostream>
#include <memory>
class Bar
{
public:
Bar() {};
~Bar() {};
void print() {
std::cout << "hello";
}
};
class Foo
{
public:
Foo();
~Foo();
void use() {
pteste->print();
}
private:
std::unique_ptr<Bar> pteste;
};
#endif
main.cpp
#include <memory>
#include "foo.h"
int main(int argc, char *argv[])
{
Foo s;
s.use();
return 0;
}
Why and how does it works "normally"?
Thanks
EDIT: I understand about the incomplete types, but what happens when I can use unique_ptr without using new and why works
EDIT2: Organized the code better for my question
Short answer: It doesn't work.
This reference says that the default constructor of std::unique_ptr creates an empty unique pointer, meaning it has no associated object.
The reason why this code prints hello is because this statement
std::cout << "hello";
doesn't need anything of Bar. It could just as well be a static method. Maybe the compiler inlines the function and replaces s.use() with the std::cout-statement. But even if it does call the method, you won't notice any errors since it doesn't access the memory of Bar at all.
Make a slight change to your class and you will see what I mean:
class Bar
{
public:
Bar() : data(10) {};
~Bar() {};
void print() {
std::cout << "hello, data is: " << data;
}
int data;
};
Now, print accesses invalid memory, because you never called new (or even better: make_unique). It may even work and print something to the console, but the output of data will be garbage. If you're lucky, the application will crash.
Another reason why it appears to work (thanks Stas):
std::unique_ptr defines operator->, which simply returns the contained pointer, but does not check if the pointer points to valid memory. So pteste-> won't throw an exception.
Yes, this code will "normally" print "hello" to console and it is not related to unique_ptr. You can replace std::unique_ptr<Bar> pteste with Bar* pteste in Bar and get the same result.
Consider how pteste->print() is called.
You can think about Bar::print() as a free function that take pointer to Bar object:
void print(Bar* this) {
std::cout << "hello";
}
See, pointer passed to print(Bar*) is never touched, so you can theoretically pass whatever you want (null, garbage etc.) and it will print "hello" to console.
It works because
std::unique_ptr<Bar> pteste;
is a pointer declaration to the instance, it does not instantiate the pointer so it does not need to know at this point the details about Bar (e.g. ctor).
In the case of
Bar pteste
in order for pteste to be constructed it will need the know definition but since Bar is only forward declared it will give an error.
All pointers are implemented the same way. Even though you have pointers to different types, all are the size of an int usually. So the compiler does not need to know about the type of the pointee when it compiles your code. Now if you were to dereference that pointer that would be a different story. Even if you would initialize your unique_ptr it would need to know the type, since new needs to see the constructor.
Related
I have just started using std::variant in my projects. I have a doubt. What will the destructor of std::variant do in the code shown below. Variant holds a void* data. Once variant goes out of scope, I think it will only free the memory of void* but not the actual object the pointer was pointing to. So there will be memory leak in this case. I would like to know if my understanding is correct or not.
#include <iostream>
#include <memory>
#include <variant>
using namespace std;
class A {
public:
~A(){
cout<<"Destructor called"<<endl;
}
};
int main() {
std::variant<void*> data;
A* b = new A();
data = (void*)b;
return 0;
}
When the variant destructor fires, it will call the destructor for whatever type of item is stored in the variant at that point. If that’s a void*, then C++ will say “okay, I will clean up the void*, and since that’s a primitive type, that’s a no-op.” It won’t look at the void*, realize that it’s actually a pointer to an A, and then delete the pointer as though it’s an A*.
The comments have pointed out that it’s fairly unusual to use a variant of a void*. A void* means “I’m pointing at something, and it’s up to you as the user to keep track of what it is and do the appropriate casting and resource management.” A variant means “I’m holding one of the following actual things, and I want C++ to remember which one and to do the appropriate resource management for me.” You may want to rethink your design, as there might be an easier way to do whatever you’re aiming to do here.
You are correct. The only pointer owning classes in the standard library that actually does delete (or delete[]) on pointers are the smart pointers.
std::variant is supposed to support you to hold one object of any number of types and primarily not pointers to objects. If the variant contains pointers, it means that some other object owns the data and is responsible for deleting it.
A std::variant capable of holding only one type is rarely useful either. You can declare the variable as a normal variable of that type in that case.
Here's one example of using a std::variant capable of holding objects of two unrelated types, and destruction will happen as expected.
#include <iostream>
#include <variant>
class A {
public:
~A() { std::cout << "A destructor called\n"; }
};
class B {
public:
B() {}
B(const B&) = default;
B& operator=(const B&) = default;
~B() { std::cout << "B destructor called\n"; }
};
int main() {
std::variant<A, B> data; // now holds a default constructed A
data = B(); // deletes the A and now holds a default constructed B
std::cout << "---\n";
}
Output:
A destructor called // in "data = B()", the A must be destroyed
B destructor called // the temporary B used in "data = B()"
---
B destructor called // the B in the variant when the variant goes out of scope
#include <iostream>
#include <memory>
class Base
{
public:
virtual void foo() = 0;
};
class Derived : public Base
{
public:
void foo() override { std::cout << "Derived" << std::endl; }
};
class Concrete
{
public:
void Bar() { std::cout << "concrete" << std::endl; }
};
int main()
{
std::unique_ptr<Concrete> ConcretePtr = nullptr;
ConcretePtr->Bar();
std::unique_ptr<Base> BasePtr;
BasePtr->foo();
return 0;
}
I assume declaring a unique_ptr to a concrete type Concrete, allocates memory for an object of type Concrete and the unique_ptr starts pointing to it. Is my assumption/understanding correct ? I ask because ConcretePtr->Bar(); prints "concrete" to the console. But, if I make a unique pointer to an interface Base, it does not know the exact type of object that I need and does not allocate/acquire resources in the memory.
This fails at BasePtr->foo(); with BasePtr._Mypair._Myval2 was nullptr.
Why does the first declaration std::unique_ptr<Concrete> ConcretePtr = nullptr; allocate an object by itself ? what if I did not want it to be pointing to some real object at that very line of code, but wanted only a smart pointer ?
Now if I change the declaration to be std::unique_ptr<Concrete> ConcretePtr; and the Concrete type to be the following,
class Concrete
{
int ConcreteNum;
public:
void Bar()
{
std::cout << "concrete" << std::endl;
ConcreteNum = 38;
std::cout << ConcreteNum << std::endl;
}
};
it fails at ConcreteNum = 38; complaining that this was nullptr; if this this was nullptr then why and how did the earlier call (where Concrete did not have any state ConcreteNum) to Bar work ?
Moreover why does it not fail at ConcretePtr->Bar(); (this -> requires a concrete object, does it not ? what was this here ?) but inside Bar, in that assignment ?
I see the same issue with std::shared_ptr as well. I'm not very sure of the difference between declaration, initialization & assignment. Please help me understand.
I'm using MSVC.
The unique_ptr models a pointer. That is, it's an object that points to another object.
Initialising the unique_ptr with nullptr creates it in the state where it is not pointing to or owning another object.
It's like saying Concrete* p = nullptr.
Initialise it in one of these ways:
std::unique_ptr<Concrete> p{new Concrete()};
or
std::unique_ptr<Concrete> p; // = nullptr is implied.
p.reset(new Concrete());
or, better:
std::unique_ptr<Concrete> p = std::make_unique<Concrete>();
or simply:
auto p = std::make_unique<Concrete>();
But be careful in this case if you really want to be pointing to the Base interface:
std::unique_ptr<Base> p = std::make_unique<Derived>();
or
std::unique_ptr<Base> p = nullptr;
p = std::make_unique<Derived>(); // assignment from rvalue ref of compatible unique_ptr.
std::unique_ptr<Concrete> ConcretePtr = nullptr;
I assume declaring a unique_ptr to a concrete type Concrete, allocates memory for an object of type Concrete and the unique_ptr starts pointing to it. Is my assumption/understanding correct ?
Well, you can trivially check. Write a default constructor for Concrete that prints something out so you can tell when an instance is created. Run the smallest possible program (just the line above in main). Did you see the expected output?
You should be checking this stuff before asking a question (and probably after reading the documentation), but to save you time: no, that line doesn't construct an object of type Concrete.
You can also check explicitly whether unique_ptr is managing an object, with
if (!ConcretePtr) {
std::cout << "ConcretePtr doesn't point to anything\n";
} else {
std::cout << "ConcretePtr owns an object\n";
}
This check is also trivial, and you could easily do it before asking a question.
I ask because ConcretePtr->Bar(); prints "concrete" to the console
This is a bad test because if the pointer is a nullptr, it's undefined behaviour. If you care whether the pointer is a nullptr, you should check that explicitly before dereferencing it, as above.
To demonstrate why this test is confusing you (and you should use the ones above in preference), consider a likely implementation of non-virtual member functions (recall they get an implicit this pointer):
// void Concrete::Bar() implemented as
void Concrete_Bar(Concrete *this)
// and ConcretePtr->Bar() implemented as
Concrete_Bar(ConcretePtr.get());
so, you just passed a nullptr to a function that ignores its only parameter, and you never tested the thing you thought you did.
std::shared_ptr has a nifty templated constructor that automagically creates the right deleter for its given type (constructor #2 in that link).
Until just now, I (erroneously) thought std::unique_ptr had a similar constructor, but when I ran the following code:
#include <memory>
#include <iostream>
// Notice nothing is virtual
struct Foo
{
~Foo() { std::cout << "Foo\n"; }
};
struct Bar : public Foo
{
~Bar() { std::cout << "Bar\n"; }
};
int main()
{
{
std::cout << "shared_ptr:\n";
std::shared_ptr<Foo> p(new Bar()); // prints Bar Foo
}
{
std::cout << "unique_ptr:\n";
std::unique_ptr<Foo> p(new Bar()); // prints Foo
}
}
I was surprised to learn that unique_ptr doesn't call Bar's destructor.
What's a clean, simple, and correct way to create a unique_ptr that has the correct deleter for its given pointer? Especially if I want to store a whole list of these (i.e. std::vector<std::unique_ptr<Foo>>), which means that they all must have a heterogeneous type?
(pardon the poor title; feel free to suggest a better one)
You should make the destructor of Foo virtual. That is good practice regardless of whether you use unique_ptr or not. That will also take care the problem that you are dealing with.
Here's one way:
{
std::cout << "unique_ptr<Bar, void(void*)>:\n";
std::unique_ptr<Foo, void(*)(void*)> p(
new Bar(), [](void*p) -> void { delete static_cast<Bar*>( p ); }
); // prints Bar Foo
}
A main problem with this approach is that unique_ptr supports conversion to logical "pointer to base class", but that the standard does not guarantee that conversion to void* will then yield the same address. In practice that's only a problem if the base class is non-polymorphic while the derived class is polymorphic, introducing a vtable ptr and thus possibly changing the memory layout a bit. But in that possible-but-not-likely situation the cast back in the deleter would yield an incorrect pointer value, and bang.
So, the above is not formally safe with respect to such conversions.
To do roughly the same as a shared_ptr does (shared_ptr supports conversions to logical pointer-to-base), you would need to store also the original void* pointer, along with the deleter.
In general, when you control the the topmost base class, make its destructor virtual.
That takes care of everything.
I have some methods that take a reference to a given object, and some are taking boost::shared_ptr. So far in my test method I created a shared_ptr pointing to one of these objects and pass *ptr to the methods expecting a reference. Is it possible to do it the other way round, e.g. create a local object on the stack, and then create a shared pointer to it in a safe way, to arrive at the straightforward alternative to &obj operator with traditional pointers?
If you find you need this, something is probably horribly wrong with your code.
If the functions take a shared pointer, it should be because they need to extend the lifetime of the object. If they don't need to extend the lifetime of the object, they should take a reference.
With what you're doing, they can't extend the lifetime of the object. If they need to, and can't, they may wind up accessing an object that has gone out of scope through a copy of the shared pointer you passed them. Boom.
It's slightly possible this might make sense. It may be that they need to extend the lifespan but you will make sure that the object remains valid longer than the longest they might possibly need to extend it. But I'd still strongly suggest not doing this. It's incredibly fragile and makes all the code you call dependent on exactly how the calling code behaves.
#include <boost/shared_ptr.hpp>
void null_deleter(int *)
{}
int main()
{
int i = 0;
boost::shared_ptr<int> p(&i, &null_deleter);
}
You can pass an appropriate deleter in the constructor of the form:
template<class Y, class D> shared_ptr(Y * p, D d);
The deleter object must do nothing in its operator()(), such as the function:
template <typename T>
void no_op(T*) {}
with which you can then construct:
boost::shared_ptr<Foo> f(&obj, no_op<Foo>);
You can use c++11 lambda function:
boost::shared_ptr<Foo> f(&obj, \[ ](Foo*){});
You can pass null_deleter in the constructor.
#include <boost/shared_ptr.hpp>
#include <boost/core/null_deleter.hpp>
int main()
{
int a = 0;
boost::shared_ptr<int> pi(&a, boost::null_deleter());
}
But watch this case: using object after destruction:
#include <boost/shared_ptr.hpp>
#include <boost/core/null_deleter.hpp>
class Y
{
public:
void tryUse()
{
std::cout << "attempt to use :"<< (uintptr_t)(void*)this<< std::endl;
}
~Y()
{
std::cout << "destructor: "<< (uintptr_t)(void*)this<< std::endl;
}
};
struct Y_user
{
boost::shared_ptr<Y> p;
~Y_user()
{
std::cout << "Y_user destructor: "<< (uintptr_t)(void*)this<< std::endl;
if (p.get())
p->tryUse();
}
};
int main()
{
{
Y_user yu;
Y y;
boost::shared_ptr<Y> p (&y, boost::null_deleter() );
yu.p = p;
}
}
Will lead to console output like this:
destructor: 140737179995232
Y_user destructor: 140737179995264
attempt to use :140737179995232
I can't remember what it is called, but I know i can do it in Java.
Suppose I have the following:
class Foo
{
public:
Foo() {};
void bar() {};
};
I want to do this:
int main() {
(new Foo).bar();
}
But it doesn't seem to work. Is there a similar way to do this without having to do:
int main() {
Foo foobar;
foobar.bar();
}
new dynamically-allocates memory and returns a pointer. Class members are obtained using the indirection operator ->. I don't think this is what you're looking for as you run the risk of causing a memory leak. Simply calling the constructor of Foo allows us to do what we want:
Foo().bar();
By calling the constructor of Foo, we create a temporary object off of which we can obtain its data members. This is preferred over pointers as we don't have to deal with memory leaks and deletion of the pointer.
You can say (new Foo)->bar();. That works but is absolutely idiotic. The correct thing is this:
int main()
{
Foo x;
x.bar();
}
Or, if you don't want the local variable: Foo().bar();. But now that's questionable, since if you don't need Foo to be stateful, then you probably don't need a class at all. Just make bar a free function (something that doesn't exist in Java):
void bar();
int main()
{
bar();
}
Yes, Foo().bar();. No need to use new like in Java.