I need to use a library which defined a register_cb function taking a void* as it's parameter:
void register_cb(void* data, ...) {
}
Now I wish to pass it some data which I'm not storing on stack, easy way to illustrate is to call this from another function:
void my_processor_fn() {
Foo foo;
register_cb(&foo); //Invalid as foo will go out of scope.
}
So I can use the heap:
void my_processor_fn() {
Foo* foo = new Foo();
register_cb(foo); //Valid but I'll have to call delete to avoid memleak
}
And I can also use smart pointers:
void my_processor_fn() {
std::unique_ptr<Foo> foo(new Foo());
register_cb(&foo); //Invalid, as unique_ptr will go out of scope and will delete foo.
}
How can I leverage smart pointers in these situation when I need to pass void* to a library function, and later the library will call my callback function with the address I have passed into register_cb?
Usually you can extend the lifetime of such objects by putting them in a class. Something like:
class MyProcess {
public:
MyProcess() : data_{std::make_unique<Foo>()} {}
void my_processor_fn() {
register_cb(data_.get());
}
private:
std::unique_ptr<Foo> data_;
};
If you make this object then use it, everything will stay alive for you:
int main() {
MyProcess my_process{};
my_process.my_processor_fn();
// pressumably some spinner that keeps the process alive while callbacks happen.
}
Related
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.
How do you delete an instantiated object inside a function then delete when another function is called?
For example:
int function_test(){
object* a = new object();
}
int function_test2(){
delete a;
}
Object a needs to be deleted when function_test2() is called. Function_test() creates and sets the value of object a.
In order to delete something, you need a pointer to something.
When you allocate an object in function function_test and want to delete it in function_test2 you need to take care of a way for function_test2 to get a hold of the pointer to the object you wish to delete.
There are multiple ways of doing that, but the most common one is for function_test to return the pointer to the caller, and then passing that pointer to function_test2:
object* function_test() {
object* a = new object();
...
return a;
}
void function_test2(object* a) {
...
delete a;
}
The caller would need to "transfer" the pointer, like this:
object obj = function_test();
...
function_test2(obj);
Other ways of transferring the pointer are using file-static pointers, using global pointers, and using instance variables when functions function_test and function_test2 are member functions of a class.
You can't transfer local variables between functions. If you like to do something like this, I suggest you return the pointer, so you can pass it to the next function.
object *function_test()
{
auto *o = new object{};
return o;
}
however, this has as disadvantage that you have to capture this variable everywhere where you call it and have to to do memory management. Most likely you just want to use something object oriented, similar to:
class ObjectOwner final
{
public:
int function_test(){
a = new object();
}
int function_test2(){
delete a;
}
private:
object *a{nullptr};
};
which can be used as:
ObjectOwner owner;
owner.function_test();
owner.function_test2();
Even better would be using a std::unique_ptr<object> so that when you forget to call the 2nd function, the memory is freed.
Finally, you can consider using a constructor/destructor.
class ObjectOwner final
{
public:
ObjectOwner()
: a(std::make_unique<object>())
{
}
~ObjectOwner() = default;
void func() { /*Do something with a*/ }
private:
std::unique_ptr<object> a{};
};
Allowing you to write:
ObjectOwner owner{};
owner.func();
Base abstract class:
class Satellite
{
public:
Satellite();
virtual void center()=0;
virtual ~Satellite(){}
};
First derived class
class Comm_sat:public Satellite
{
public:
Comm_sat();
void center() override{cout << "comm satellite override\n";}
};
Second derived class
class Space_station:public Satellite
{
public:
Space_station();
void center() override{cout << "space station override\n";}
};
Pointer version of the functions
void f(Satellite* ms){
ms->center();
delete ms;
}
int main()
{
Comm_sat* cs = new Comm_sat;
Space_station* ss = new Space_station;
f(cs);
f(ss);
}
The objects created using new in main() are properly destroyed in f(), right?
Reference version of the functions
void f(Satellite& ms){
ms.center();
}
int main()
{
Comm_sat cs;
Space_station ss;
f(cs);
f(ss);
}
Is the reference version better?
Besides, I try to use unique_ptr, however, I get errors
void f(Satellite* ms){
ms->center();
}
int main()
{
unique_ptr<Comm_sat> cs{new Comm_sat};
unique_ptr<Space_station> ss{new Space_station};
f(cs);
f(ss);
}
Error: cannot convert std::unique_ptr<Comm_sat> to Satellite* for argument 1 to void f(Satellite*)
Error: type class std::unique_ptr<Comm_sat> argument given to delete, expected pointer delete cs;
Same error for the other derived class.
Is the reference version better?
Yes, although a better way to put this would be "the pointer version is worse". The problem with the pointer version is that you pass it a valid pointer, and get a dangling pointer when the function returns. This is not intuitive, and leads to maintenance headaches when someone modifies your code thinking that you have forgotten to delete cs and ss in the main, not realizing that f deletes its argument.
The version that uses a reference is much better in this respect, because the resources are managed automatically for you. Readers of your code do not need to track the place where the memory of cs and ss gets released, because the allocation and release happen automatically.
I try to use unique_ptr, however, I get errors
There is no implicit conversion from std::unique_ptr<T> to T*. You need to call get() if you want to pass a raw pointer:
f(cs.get());
f(ss.get());
The objects created using new in main() are properly destroyed in f(), right?
They're destroyed, and cleaned up correctly, yes. "Properly" is a stretch though, since all this manual-new-and-delete-raw-pointers stuff is poor style.
The reason unique_ptr isn't working for you is that ... it's a unique_ptr, not a raw pointer. You can't just pass it as a raw pointer.
Try
void f(Satellite* ms){
ms->center();
}
// ...
f(cs.get());
or better, unless you really need to pass nullptr sometimes,
void f(Satellite& ms){
ms.center();
}
// ...
f(*cs);
or best of all, since you don't show any reason to require dynamic allocation at all:
void f(Satellite& ms);
// ...
{
Comm_sat cs;
f(cs);
} // no new, no delete, cs goes out of scope here
I have following code:
class A{
public:
virtual do_something() = 0;
}
class B : public A{
public:
virtual do_something() override;
}
void use_a(A *a){
if (a){
a->do_something();
delete a;
}
}
use_a( new B() );
How this can be translated to references?
Notice do_something() is not const method.
I thought it can be something like this:
void use_a(A &&a){
a->do_something();
}
use_a( B() );
but someone told me this is bad style and must be avoided.
Rvalue references have move sematics. That does not work well when moving B as A.
Use lvalue reference:
void use_a(A &a);
B b;
use_a(b);
or a template:
template <typename T>
void use_a(T &&a);
or, if it doesn't need to be a reference, a smart pointer:
void use_a(std::unique_ptr<A> a);
void use_a(std::shared_ptr<A> a);
Quite simply you convert from a pointer to a reference by providing a concrete instance, i.e. you dereference:
void f(int& i);
f(*(new int)); // do not do this!
The problem is that raw pointers in C++ are precisely that - they do not have automatic lifetime scope, and by converting to an lvalue reference, you have suggested a contract that the instance is concrete and should not be destroyed by the receiver.
int* ptr = new int;
f(ptr);
delete ptr; // otherwise it leaked
Modern C++ uses RAII to provide controlled automatic lifetime management, and C++11 introduced unique_ptr and shared_ptr for handling pointers. With C++14 we also have the mechanisms to avoid raw pointers entirely.
std::unique_ptr<int> ptr = std::make_unique<int>(/* ctor arguments here */);
f(ptr.get());
// now when ptr goes out of scope, deletion happens automatically.
See also http://en.cppreference.com/w/cpp/memory/unique_ptr
Only one std::unique_ptr should have the address of a given allocation at any time (it assumes ownership and will delete the allocation on exiting scope if it's not released).
For a ref-counted pointer: http://en.cppreference.com/w/cpp/memory/shared_ptr
--- EDIT ---
Based on the OPs comments:
Firstly note that
Pair p = { "one", "two" };
// and
Pair p("one", "two");
Pair p{"one", "two"};
are synonymous, in all cases they create a stack-local variable, p, by allocating stack space and calling Pair::Pair("one", "two") to construct a Pair object there.
Remember, however, that this is a stack variable - it has an automatic lifetime and will expire at the end of the current scope.
{ Pair p{"one", "two"}; list_add(list, p); } //p is destroyed
In theory, you can replace this with
list_add(list, Pair{"one", "two"});
But what matters is whether list_add expects you to keep the object around until you remove it from the list... That is often what a list-based function that takes a pointer is expecting. If it takes a non-const reference, it may do the same.
To answer your original post::
struct A { virtual void doSomething() {} };
struct B : public A { virtual void doSomething() override() {} };
void useDoSomethingInterface(A& a) {
a.doSomething();
}
int main() {
A a;
B b;
useDoSomethingInterface(a);
useDoSomethingInterface(b);
}
consider the following:
void list_add(IList& list, Pair& pair) {
pair.next = list.head;
list.head = &pair; // << BAD NEWS
}
void badness(IList& list) {
list_add(list, Pair("hello", "world"));
}
void caller() {
IList list;
badness(list);
// list.head now points to a destroyed variable on the stack
C-pointers in C++ are raw, machine level pointers. They don't ref count. And C++ object instances have a fixed well defined lifetime: till the end of the scope.
However, if list_add is taking its data by value
void list_add(IList& list, Pair pair)
Then we'll be ok. The temporary Pair we create will have to be copied once to create pair and then copied again into the list, which is a shame but at least it won't crash.
your code is a bit unsafe.
first, what if a is null? you didn't check it.
second, what if a points to a stack-object or data-segment-object? you'll have unexpected behaviour (=crash on most of the OS).
if your object has to be dynamically alocated, just use std::shared_ptr
void use_a(std::shared_ptr<A>& a){
a->do_something();
}
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.