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
Related
#include <memory>
#include <functional>
#include <iostream>
struct TestStruct {
int a = 100;
};
struct StructDeleter {
void operator()(TestStruct *ptr) const {
delete ptr;
}
};
std::unique_ptr<TestStruct, StructDeleter> MakeNewStruct() {
std::unique_ptr<TestStruct> st(new TestStruct());
std::unique_ptr<TestStruct, StructDeleter> customDeleterSt(std::move(st));
std::cout << customDeleterSt->a << std::endl;
return customDeleterSt;
}
int main() {
auto a = MakeNewStruct();
std::cout << a->a << std::endl;
return 0;
}
The above code can not be compiled, how to move st to customDeleterSt?
I get a st unique_ptr from the st creation interface, and I use the custom deleter to hide the implementation of st from my users, so how to move a unique_ptr without custom deleter to a unique_tr with custom deleter?
Thanks for any help!
As noted in the comments, the brute-force way is to have the source .release() to the constructor of the destination. However there is a much more elegant solution (imho):
Add an implicit conversion from std::default_delete<TestStruct> to StructDeleter:
struct StructDeleter {
StructDeleter(std::default_delete<TestStruct>) {} // Add this
void operator()(TestStruct *ptr) const {
delete ptr;
}
};
Now the code works with the existing move construction syntax.
Whether this is done via the converting constructor, or .release(), if StructDeleter can't (for whatever reasons) properly delete a pointer that std::default_delete handles, this will result in undefined behavior. It is only because StructDeleter calls delete ptr that either of these techniques works.
As written, TestStruct does not need to be a complete type at the point of delete. However should TestStruct acquire a non-trivial destructor, you will also need to ensure that for any code that calls StructDeleter::operator()(TestStruct*), that TestStruct is a complete type, otherwise you're back into UB territory again. This assurance is one of the things that std::default_delete<TestStruct> does for you and that StructDeleter (as written) does not.
If it is intended to keep ~TestStruct() trivial, it would be a good idea to add:
static_assert(std::is_trivially_destructible<TestStruct>::value);
In the following code example:
#include <iostream>
class Foo{
};
class Bar{
public:
void addFoo(Foo *foo){
auto my_foo = std::shared_ptr<Foo>(foo);
}
};
int main() {
auto bar = Bar();
bar.addFoo(new Foo());
return 0;
}
Do I need to clean up the pointer created in main() by the bar.addFoo(new Foo) call, or will this be taken care of by Bar which creates a shared_ptr of it? My understanding is that auto my_foo = std::shared_ptr<Foo>(foo); will use the copy constructer to copy this pointer into my_foo leaving the original one dangling, is that correct?
The very idea of a constructor taking a raw pointer is to pass the ownership to std::shared_ptr. So, no, you don't have to delete a raw pointer passed to std::shared_ptr. Doing this will lead to a double deletions, which is UB.
Note that in general passing a raw pointer is dangerous. Consider the following more generalized example:
void addFoo(Foo *foo){
// some code which could throw an exception
auto my_foo = std::shared_ptr<Foo>(foo);
}
If an exception is throw before my_foo is constructed, foo will leak.
If you have no special reason to pass a raw pointer, consider the following alternative:
class Bar {
public:
template<class... Args>
void addFoo(Args... args){
auto my_foo = std::make_shared<Foo>(args...);
}
};
int main() {
auto bar = Bar();
bar.addFoo();
return 0;
}
Here you pass arguments (if you have any) to construct Foo inside addFoo() instead of constructing Foo before invoking addFoo().
Perfect forwarding of args... could be used if it is needed:
template<class... Args>
void addFoo(Args&&... args){
auto my_foo = std::make_shared<Foo>(std::forward<Args>(args)...);
}
The code you wrote is correct. But in modern C++, you should not be using raw pointers, new and delete unless you have to interoperate with code that does. If you can help it (and if question comments are any indication, you can), use smart pointers all the way through:
#include <iostream>
#include <memory>
class Foo {};
class Bar {
public:
void addFoo(std::unique_ptr<Foo> foo) {
auto my_foo = std::shared_ptr<Foo>(std::move(foo));
}
};
int main() {
auto bar = Bar();
bar.addFoo(std::make_unique<Foo>());
return 0;
}
Above, the addFoo member function receives the pointer as a unique_ptr, and uses std::move to transfer ownership of the pointer from the unique_ptr to the shared_ptr without copying the referent; after constructing the shared_ptr, the unique_ptr is left in an empty state. You could also have addFoo receive a shared_ptr directly, or construct the object in-place inside the member function, as in Evg’s answer.
Using unique_ptr instead of a raw pointer makes it clear that the method intends to take ownership of the allocation, and encourages callers to use smart pointers themselves, making it less likely they will forget to delete their allocations later.
A raw pointer does not manage end of life, but a shared pointer does. When you create a shared pointer from a raw pointer, the shared pointer takes ownership of the object. That means that the object will be destroyed when the last shared pointer pointing to it will go out of scope.
In your code, my_foo takes ownership of the object created with new Foo(), goes out of scope when addFoo returns, and as it contains the only shared reference, correctly destroys the object.
The correct, c++ way to do this, would be the following:
#include <iostream>
class Foo{
};
class Bar{
public:
void addFoo(Foo foo){
auto my_foo = std::make_shared<Foo>(foo);
}
};
int main() {
auto bar = Bar();
bar.addFoo(Foo());
return 0;
}
This avoids any raw pointers or naked new, and is totally exception safe. Also, std::make_shared introduces some performance benefits.
One confusing thing here is that the code seems to be unnecessarily copy the Foo object, however, since C++17, due to Return Value Optimization, (RVO), you are guaranteed to have no copies at all (when passing Foo as an argument to addFoo).
You can create the shared pointer with make_shared. If you want to construct Foo in main (e.g. because you have the paramters available there), then use make_shared at the point of construction and pass the shared_ptr on.
#include <iostream>
class Foo{
~Foo() { std::cout << "Foo destructed" << std::endl; }
};
class Bar{
public:
void addFoo(std::shared_ptr<Foo> foo){
auto my_foo = foo;
}
};
int main() {
auto bar = Bar();
bar.addFoo(std::make_shared<Foo>());
return 0;
}
delete also calls your destructor. You can test, whether the shared pointer destructs your object or whether a delete is needed by printing out a message.
Is it in anyway possible (without using boost) to have a function in c++ as follows :
void foo(int x, classX &obj = *(new classX()))
The classX is used multiple times in my codebase and there are many such functions which have a similar signature (i.e. use this class object as a default argument). Is it possible to achieve this without an overloaded call?
The code that you provided certainly compiles and "works", but I strongly advise against such a thing.
The function returns void so that means the either referenced or allocated object (or its presumed owner) does not leave the function. It must thus, if allocated, be destroyed (otherwise, that's someone else's problem, outside that function).
However, that isn't even possible, there is nobody who owns the object, or has a pointer to it! So not only do you have a possible memory leak there, you have a guaranteed memory leak (in case no object is passed), unless you add yet another ugly hack that derives a pointer from the reference only to destroy the object. That's very unpleasant.
Plus, even if you get this done (in a no-leak way), you have useless object allocation and destruction for every function call. Although one shouldn't optimize prematurely, one also shouldn't pessimize prematurely by adding regular allocations and deallocations that are not just unnecessary but actually decrease code quality.
Something that's better would be:
//namespace whatever {
classX dummy;
//}
#include <memory>
void foo(int x, classX &obj = dummy)
{
if(std::addressof(obj) != std::addressof(dummy))
{ /* do something using object */ }
else
{ /* no object supplied */ }
}
Yep, that's a global used for a good cause. You can make the global a singleton if that makes you feel better, or a static class member, all the same. Either way, you have exactly one object, no allocations, no leaks, and you can still pass an object to the function if you wish. And, you can distinguish these two cases.
To use a global shared instance as default argument is possible.
With
extern inline classX globalClassX;
void foo(int x, classX &obj = globalClassX);
it should be accomplished.
However, I'm quite uncertain about the static initialization order fiasco which may interfere.
This can be solved using Meyers Singleton approach instead:
classX& getGlobalClassX()
{
static ClassX classX;
return classX;
}
void foo(int x, classX &obj = getGlobalClassX);
An MCVE for demonstration:
#include <cassert>
#include <iostream>
struct Object {
inline static unsigned idGen = 1;
unsigned id;
const std::string name;
explicit Object(const std::string &name = std::string()): id(idGen++), name(name) { }
};
Object& getGlobalObj()
{
static Object objGlobal("global");
return objGlobal;
}
void doSomething(int x, Object &obj = getGlobalObj());
#define PRINT_AND_DO(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
PRINT_AND_DO(doSomething(0));
PRINT_AND_DO(Object obj("local"));
PRINT_AND_DO(doSomething(1, obj));
PRINT_AND_DO(doSomething(2));
}
void doSomething(int x, Object &obj)
{
std::cout << "doSomething(x: " << x << ", obj: Object("
<< obj.id << ", '" << obj.name << "'))\n";
}
Output:
doSomething(0);
doSomething(x: 0, obj: Object(1, 'global'))
Object obj("local");
doSomething(1, obj);
doSomething(x: 1, obj: Object(2, 'local'))
doSomething(2);
doSomething(x: 2, obj: Object(1, 'global'))
Live Demo on coliru
Another Q/A I consulted while writing:
SO: Are static data members safe as C++ default arguments?
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.
I'm using a library which returns a reference to me.
I need to use this reference as class-attribute.
Not being able to initialize the attribute in constructor directly (the lib needs to be inited before), I thought about using a shared_ptr for lazy initialization:
#include <iostream>
#include <string>
#include <tr1/memory>
//This is library, cannot touch
std::string globalString = "TEST";
std::string& getStringReference()
{
return globalString;
}
//this is my class which uses the library
class Foo
{
public:
Foo() :
testString_( std::tr1::shared_ptr< std::string& >() )
{
//do some initialization of the library here...
//now init the shared_ptr
testString_.reset( getStringReference() );
}
std::string getString() const
{
return *testString_;
}
private:
std::tr1::shared_ptr< std::string& > testString_;
};
//and a main to be compilable and check if the above works...
int main()
{
Foo foo;
std::cout << foo.getString() << std::endl;
}
But unfortunately this does not work. g++ gives messages like this:
error: forming pointer to reference type ‘std::string&’
I tried some other ways to get the reference into the shared_ptr, but nothing works... Perhaps you could give me a hint.
Note:
- In "real-world" instead of std::string the datatype is a class without default constructor.
- For those who still wonder: The above is just a simplified example-code :)
UPDATE:
- While trying to apply the suggestions, I found out that contrary to the used std::string from example, my class has a private copy constructor. This means I'm not able to just copy the object into a new one.
If you are provided by a reference only, that means that you are not responsible for memory management, and that in turns means that you cannot use your own memory management. That is, you should not use any type of smart pointer to hold that object.
While you can obtain the address of the real object with the & operator, doing so will cause undefined behavior later on when your shared_ptr goes out of scope and tries to free the memory and the library itself tries to free the memory on it's own.
You simply cannot take the address of a reference.
You can however use shared_ptr<string> and initialize it with &getStringReference. But that will cause the shared_ptr to try to delete the string, causing it to fail since it was never allocated using new. To fix this, make a copy:
testString_.reset(new std::string(getStringReference()))
Even better, let your class just store the reference directly. The you don't need to bother about memory management at all:
class Foo
{
std::string& _testString;
// ...
}
You need to understand the semantics of references and of memory management.
What you probably want is a raw pointer in your class. I assume you can't use a reference because you do not know what object it will refer to until you make the function call so you want to do something like ref=getRef();
You have no way of automatically "protecting" your pointer against becoming "dangling", but do not think there is anything you can do to rectify this situation. You just have to look at the documentation as to how to use the reference/pointer properly.
You could consider using Boost.Optional, which support optional references. This way, you could lazy initialize your reference without taking ownership of the referenced object as you do by using shared_ptr:
#include <iostream>
#include <string>
#include <boost/optional.hpp>
//This is library, cannot touch
std::string globalString = "TEST";
std::string& getStringReference()
{
return globalString;
}
//this is my class which uses the library
class Foo
{
public:
Foo()
{
//do some initialization of the library here...
//now init the optional reference
testString_.reset( getStringReference() );
}
std::string getString() const
{
return *testString_;
}
private:
boost::optional< std::string& > testString_; //<-- note the use of optional
};
//and a main to be compilable and check if the above works...
int main()
{
Foo foo;
std::cout << foo.getString() << std::endl;
}
Stop using shared_ptr now. Sharing is not an unilateral decision.
That being said, you are returned a reference to an object, not the object proper. There are two things you can do:
copy the object, and therefore deciding to manage the lifetime of the copy yourself
take a reference to the object, and let it up to the library you called to manage the lifetime, in which case you'll need to have some knowledge about it
I would definitely recommend copying unless there is a reason not to, much easier to get it right.
If you go for copying, use boost::optional<LibObject> within your class, this way you'll bypass the initialization issue.
If you wish to use a reference, you can still use boost::optional, and it'll work too! Use it as such: boost::optional<LibObject&>, but make sure the object you have a reference to will live long enough.
Finally, regarding the initialization issue, you could use a function to process the initialization and return a reference directly, thus initializing the reference of your class in the initialization list.
You can not use a shared_ptr with a reference type, because a reference is just that - a reference to an object. It is not a real object.
Next example is just simplified version of what you tried to do :
int main()
{
int &* a;
}
Use a factory function?
class Library
{
public:
static void Init();
static LibraryThing & getThing();
};
class Foo
{
public:
static shared_ptr<Foo> Create()
{
if (!_libInit)
{
Library::Init();
_libInit = true;
}
return make_shared(new Foo(Library::getThing()));
}
private:
Foo(LibraryThing & ref) : _ref(ref)
{
}
private:
LibraryThing & _ref;
static bool _libInit;
};