Accessing object T in vector<unique_ptr<T>> without taking ownership - c++11

I have the following member variable in a class:
std::vector<std::unique_ptr<Object>> objects_;
I explicitly want the vector to maintain ownership at all times. I've seen suggestions that in order for a member function to access a pointer in the vector and make changes to the object T wrapped in the std::unique_ptr, we must move the pointer to calling code, i.e:
void foo(int i) {
auto object = std::move( vector.at( i ) ); // move object to caller (caller owns)
object->dosomething();
vector.at(i) = std::move(object); // move back into vector (vector owns)
}
Another method was to work with raw pointers:
void foo(int i) {
Object* object = vector.at( i ).get();
object->doSomething();
}
However, I've been working with this:
void foo(int i) {
auto& object = vector.at( i );
object->doSomething();
}
Which is the correct and most robust method for my case? Does this function ever take ownership of the data in the std::unique_ptr? Is there a way to access Object without playing with the std::unique_ptr?
(excuse me if my methods are incorrect, I hope I got the point across)

The first approach will not retain ownership of the object if object->dosomething() throws an exception (i.e. it is not exception safe) since the second std::move() statement will not be executed.
Assuming C++11, both of the other approaches are effectively equivalent, subject to the assumption that the owned pointer is not null. Under the same assumption, the code can be simplified to
void foo(int i)
{
vector.at(i)->doSomething();
}
which will work with all C++ standards (not just C++11 or later).
It is possible to access the object without monkeying with the unique_ptr - simply store the pointer elsewhere and use that. However, that does compromise the purpose of using std::unique_ptr in the first place. And is error-prone - for example, the std::unique_ptr can destroy the object, and leave those other pointers dangling.
If you are really that worried about the potential of your vector losing ownership, consider using a shared_ptr instead.

Related

Removing a std::function<()> from a vector c++

I'm building a publish-subscribe class (called SystermInterface), which is responsible to receive updates from its instances, and publish them to subscribers.
Adding a subscriber callback function is trivial and has no issues, but removing it yields an error, because std::function<()> is not comparable in C++.
std::vector<std::function<void()> subs;
void subscribe(std::function<void()> f)
{
subs.push_back(f);
}
void unsubscribe(std::function<void()> f)
{
std::remove(subs.begin(), subs.end(), f); // Error
}
I've came down to five solutions to this error:
Registering the function using a weak_ptr, where the subscriber must keep the returned shared_ptr alive.
Solution example at this link.
Instead of registering at a vector, map the callback function by a custom key, unique per callback function.
Solution example at this link
Using vector of function pointers. Example
Make the callback function comparable by utilizing the address.
Use an interface class (parent class) to call a virtual function.
In my design, all intended classes inherits a parent class called
ServiceCore, So instead of registering a callback function, just
register ServiceCore reference in the vector.
Given that the SystemInterface class has a field attribute per instance (ID) (Which is managed by ServiceCore, and supplied to SystemInterface by constructing a ServiceCore child instance).
To my perspective, the first solution is neat and would work, but it requires handling at subscribers, which is something I don't really prefer.
The second solution would make my implementation more complex, where my implementation looks as:
using namespace std;
enum INFO_SUB_IMPORTANCE : uint8_t
{
INFO_SUB_PRIMARY, // Only gets the important updates.
INFO_SUB_COMPLEMENTARY, // Gets more.
INFO_SUB_ALL // Gets all updates
};
using CBF = function<void(string,string)>;
using INFO_SUBTREE = map<INFO_SUB_IMPORTANCE, vector<CBF>>;
using REQINF_SUBS = map<string, INFO_SUBTREE>; // It's keyed by an iterator, explaining it goes out of the question scope.
using INFSRC_SUBS = map<string, INFO_SUBTREE>;
using WILD_SUBS = INFO_SUBTREE;
REQINF_SUBS infoSubrs;
INFSRC_SUBS sourceSubrs;
WILD_SUBS wildSubrs;
void subscribeInfo(string info, INFO_SUB_IMPORTANCE imp, CBF f) {
infoSubrs[info][imp].push_back(f);
}
void subscribeSource(string source, INFO_SUB_IMPORTANCE imp, CBF f) {
sourceSubrs[source][imp].push_back(f);
}
void subscribeWild(INFO_SUB_IMPORTANCE imp, CBF f) {
wildSubrs[imp].push_back(f);
}
The second solution would require INFO_SUBTREE to be an extended map, but can be keyed by an ID:
using KEY_T = uint32_t; // or string...
using INFO_SUBTREE = map<INFO_SUB_IMPORTANCE, map<KEY_T,CBF>>;
For the third solution, I'm not aware of the limitations given by using function pointers, and the consequences of the fourth solution.
The Fifth solution would eliminate the purpose of dealing with CBFs, but it'll be more complex at subscriber-side, where a subscriber is required to override the virtual function and so receives all updates at one place, in which further requires filteration of the message id and so direct the payload to the intended routines using multiple if/else blocks, which will increase by increasing subscriptions.
What I'm looking for is an advice for the best available option.
Regarding your proposed solutions:
That would work. It can be made easy for the caller: have subscribe() create the shared_ptr and corresponding weak_ptr objects, and let it return the shared_ptr.
Then the caller must not lose the key. In a way this is similar to the above.
This of course is less generic, and then you can no longer have (the equivalent of) captures.
You can't: there is no way to get the address of the function stored inside a std::function. You can do &f inside subscribe() but that will only give you the address of the local variable f, which will go out of scope as soon as you return.
That works, and is in a way similar to 1 and 2, although now the "key" is provided by the caller.
Options 1, 2 and 5 are similar in that there is some other data stored in subs that refers to the actual std::function: either a std::shared_ptr, a key or a pointer to a base class. I'll present option 6 here, which is kind of similar in spirit but avoids storing any extra data:
Store a std::function<void()> directly, and return the index in the vector where it was stored. When removing an item, don't std::remove() it, but just set it to std::nullptr. Next time subscribe() is called, it checks if there is an empty element in the vector and reuses it:
std::vector<std::function<void()> subs;
std::size_t subscribe(std::function<void()> f) {
if (auto it = std::find(subs.begin(), subs.end(), std::nullptr); it != subs.end()) {
*it = f;
return std::distance(subs.begin(), it);
} else {
subs.push_back(f);
return subs.size() - 1;
}
}
void unsubscribe(std::size_t index) {
subs[index] = std::nullptr;
}
The code that actually calls the functions stored in subs must now of course first check against std::nullptrs. The above works because std::nullptr is treated as the "empty" function, and there is an operator==() overload that can check a std::function against std::nullptr, thus making std::find() work.
One drawback of option 6 as shown above is that a std::size_t is a rather generic type. To make it safer, you might wrap it in a class SubscriptionHandle or something like that.
As for the best solution: option 1 is quite heavy-weight. Options 2 and 5 are very reasonable, but 6 is, I think, the most efficient.

Is there a way to make a moved object "invalid"?

I've some code that moves an object into another object. I won't need the original, moved object anymore in the upper level. Thus move is the right choice I think.
However, thinking about safety I wonder if there is a way to invalidate the moved object and thus preventing undefined behaviour if someone accesses it.
Here is a nice example:
// move example
#include <utility> // std::move
#include <vector> // std::vector
#include <string> // std::string
int main () {
std::string foo = "foo-string";
std::string bar = "bar-string";
std::vector<std::string> myvector;
myvector.push_back (foo); // copies
myvector.push_back (std::move(bar)); // moves
return 0;
}
The description says:
The first call to myvector.push_back copies the value of foo into the
vector (foo keeps the value it had before the call). The second call
moves the value of bar into the vector. This transfers its content
into the vector (while bar loses its value, and now is in a valid but
unspecified state).
Is there a way to invalidate bar, such that access to it will cause a compiler error? Something like:
myvector.push_back (std::move(bar)); // moves
invalidate(bar); //something like bar.end() will then result in a compiler error
Edit: And if there is no such thing, why?
Accessing the moved object is not undefined behavior. The moved object is still a valid object, and the program may very well want to continue using said object. For example,
template< typename T >
void swap_by_move(T &a, T &b)
{
using std::move;
T c = move(b);
b = move(a);
a = move(c);
}
The bigger picture answer is because moving or not moving is a decision made at runtime, and giving a compile-time error is a decision made at compile time.
foo(bar); // foo might move or not
bar.baz(); // compile time error or not?
It's not going to work.. you can approximate in compile time analysis, but then it's going to be really difficult for developers to either not get an error or making anything useful in order to keep a valid program or the developer has to make annoying and fragile annotations on functions called to promise not to move the argument.
To put it a different way, you are asking about having a compile time error if you use an integer variable that contains the value 42. Or if you use a pointer that contains a null pointer value. You might be succcessful in implementing an approximate build-time code convention checker using clang the analysis API, however, working on the CFG of the C++ AST and erroring out if you can't prove that std::move has not been called till a given use of a variable.
Move semantics works like that so you get an object in any it's correct state. Correct state means that all fields have correct value, and all internal invariants are still good. That was done because after move you don't actually care about contents of moved object, but stuff like resource management, assignments and destructors should work OK.
All STL classes (and all classed with default move constructor/assignment) just swap it's content with new one, so both states are correct, and it's very easy to implement, fast, and convinient enough.
You can define your class that has isValid field that's generally true and on move (i. e. in move constructor / move assignment) sets that to false. Then your object will have correct state I am invalid. Just don't forget to check it where needed (destructor, assignment etc).
That isValid field can be either one pointer having null value. The point is: you know, that object is in predictable state after move, not just random bytes in memory.
Edit: example of String:
class String {
public:
string data;
private:
bool m_isValid;
public:
String(string const& b): data(b.data), isValid(true) {}
String(String &&b): data(move(b.data)) {
b.m_isValid = false;
}
String const& operator =(String &&b) {
data = move(b.data);
b.m_isValid = false;
return &this;
}
bool isValid() {
return m_isValid;
}
}

Code duplication for functions that take shared_ptr and unique_ptr

Problem:
Let's assume I have an algorithm that takes a unique_ptr to some type:
void FancyAlgo(unique_ptr<SomeType>& ptr);
Now I have shared_ptr sPtr to SomeType, and I need to apply the same algorithm on sPtr. Does this mean I have to duplicate the algorithm just for the shared_ptr?
void FancyAlgo(shared_ptr<SomeType>& sPtr);
I know smart pointers come with ownership of the underlying managed object on the heap. Here in my FancyAlgo, ownership is usually not an issue. I thought about stripping off the smart pointer layer and do something like:
void FancyAlgo(SomeType& value);
and when I need to call it with unique_ptr:
FancyAlgo(*ptr);
likewise for shared_ptr.
1, Is this an acceptable style in PRODUCTION code?(I saw somewhere that in a context of smart pointers, you should NOT manipulate raw pointers in a similar way. It has the danger of introducing mysterious bugs.)
2, Can you suggest any better way (without code duplication) if 1 is not a good idea.
Thanks.
Smart pointers are about ownership. Asking for a smart pointer is asking for ownership information or control.
Asking for a non-const lvalue reference to a smart pointer is asking for permission to change the ownership status of that value.
Asking for a const lvalue reference to a smart pointer is asking for permission to query the ownership status of that value.
Asking for an rvalue reference to a smart pointer is being a "sink", and promising to take that ownership away from the caller.
Asking for a const rvalue reference is a bad idea.
If you are accessing the pointed to value, and you want it to be non-nullable, a reference to the underlying type is good.
If you want it to be nullable, a boost::optional<T&> or a T* are acceptable, as is the std::experimental "world's dumbest smart pointer" (or an equivalent hand-written one). All of these are non-owning nullable references to some variable.
In an interface, don't ask for things you don't need and won't need in the future. That makes reasoning about what the function does harder, and leads to problems like you have in the OP. A function that reseats a reference is a very different function from one that reads a value.
Now, a more interesting question based off yours is one where you want the function to reseat the smart pointer, but you want to be able to do it to both shared and unique pointer inputs. This is sort of a strange case, but I could imagine writing a type-erase-down-to-emplace type (a emplace_sink<T>).
template<class T>
using later_ctor = std::function<T*(void*)>;
template<class T, class...Args>
later_ctor<T> delayed_emplace(Args&&...args) {
// relies on C++1z lambda reference reference binding, write manually
// if that doesn't get in, or don't want to rely on it:
return [&](void* ptr)->T* {
return new T(ptr)(std::forward<Args>(args));
};
}
namespace details {
template<class T>
struct emplace_target {
virtual ~emplace_target() {}
virtual T* emplace( later_ctor<T> ctor ) = 0;
};
}
template<class T>
struct emplacer {
std::unique_ptr<emplace_target<T>> pImpl;
template<class...Args>
T* emplace( Args&&... args ) {
return pImpl->emplace( delayed_emplace<T>(std::forward<Args>(args)...) );
}
template<class D>
emplacer( std::shared_ptr<T, D>& target ):
pImpl( new details::emplace_shared_ptr<T,D>(&target) ) // TODO
{}
template<class D>
emplacer( std::unique_ptr<T, D>& target ):
pImpl( new details::emplace_unique_ptr<T,D>(&target) ) // TODO
{}
};
etc. Lots of polish needed. The idea is to type-erase construction of an object T into an arbitrary context. We might need to special case shared_ptr so we can call make_shared, as a void*->T* delayed ctor is not good enough to pull that off (not fundamentally, but because of lack of API hooks).
Aha! I can do a make shared shared ptr without special casing it much.
We allocate a block of memory (char[sizeof(T)]) with a destructor that converts the buffer to T then calls delete, in-place construct in that buffer (getting the T*), then convert to a shared_ptr<T> via the shared_ptr<T>( shared_ptr<char[sizeof(T)]>, T* ) constructor. With careful exception catching this should be safe, and we can emplace using our emplacement function into a make_shared combined buffer.

How can I move a shared_ptr's data?

I have an easy question about shared pointers and move semantics. Imagine that I have a class with a private member variable like this:
class C
{
private:
std::shared_ptr<std::vector<uint8_t>> buffer;
}
I need to provide public getters and setters. The getter seems obvious:
std::shared_ptr<std::vector<uint8_t>> C::GetBuffer()
{
return buffer;
}
However, being new to C++ I'm having trouble writing the setter. I could do something like this:
void C::SetBuffer(std::shared_ptr<std::vector<uint8_t>> input)
{
buffer = input;
}
However that results in a copy of input to buffer, but I don't really want the caller to have shared ownership. Instead I want to move the data. I tried to solve this with:
void C::SetBuffer(std::shared_ptr<std::vector<uint8_t>>& input)
{
buffer(std::move(input));
}
But this is an error: "call of an object of a class type without appropriate operator() or conversion functions to pointer-to-function type."
Can somebody help me understand:
1. What is going on here?
2. How to best implement the setter?
You can fix the error you're getting by writing this:
void C::SetBuffer( std::shared_ptr<std::vector<uint8_t> > &input ) {
buffer = move(input);
}
This will call shared_ptr's move-assignment operator, which will pilfer input. However, this won't really stop the caller from having shared ownership. Once you accept (or dispense) a shared_ptr from/to an unknown client, you don't have much in the way of control about who shares ownership. Even if input is pilfered, there's no reason to expect that input was the only copy of the shared_ptr you just received. If, for example, the function that called SetBuffer() took whatever became input from its caller by value, that higher-level copy of the pointer will continue to share ownership.
Note that your getter has a similar issue. You're returning a shared_ptr to your own internal object (and what's more, it's a shared_ptr-to-non-const, so the client can modify the shared state) and wherever that shared_ptr gets passed around after you provide it, those copies will also share (mutable) ownership.
If you really want to ensure you have exclusive ownership, you can hold a unique_ptr instead of a shared_ptr and have your getter pass back a const-reference, and your setter take either a unique_ptr or a value.
If your goal is to allow a caller to pass sole ownership of a buffer to your object, you should accept it by unique_ptr instead of shared_ptr:
void C::SetBuffer(std::unique_ptr<std::vector<uint8_t>> input)
{
buffer = std::move(input);
}
Rvalue unique_ptr is convertible to shared_ptr for exactly this purpose.

function that modifies object pointed to by std::unique_ptr<T>

Somewhere in my code I have a local std::unique_ptr<T>. I need to do stuff with the object pointed at, and I use a function for that:
std::unique_ptr<T> some_function( std::unique_ptr<T> &t )
{
// do stuff
return t;
}
I call the function like this:
std::unique_ptr<T> some_T_ptr( new T(/*args*/) );
vector_of_finalized_Ts.push_back( std::move(some_function(std::move(some_T_ptr))));
Now I wonder, is there a better way to get the necessary functionality? It just seems two moves are pretty superfluous and potentially dangerous. I do have error handling code I'm not showing here, but that's beside the point.
It is all about ownership. Do you want some_function to take ownership of the pointer or not? If not, you can just pass a raw pointer to some_function. If you want some_function to take ownership (and return ownership), then it should take the unique_ptr by value. Otherwise the return statement (which should be std::move(t)) will be moving from a reference of unknown origins.
std::unique_ptr<T> some_function( std::unique_ptr<T> t )
{
// I own t here and will delete it if an exception happens
// do stuff
// I'm transferring ownership back to the caller
// (who may or may not accept ownership)
return std::move(t);
}
vector_of_finalized_Ts.push_back( some_function(std::move(some_T_ptr)));
or:
void some_function( T* t )
{
// I don't own t and won't delete it if an exception happens
// do stuff
}
some_function(some_T_ptr.get());
vector_of_finalized_Ts.push_back( std::move(some_T_ptr));
Either design is fine. It just depends on what code should own the pointer (especially if an exception is thrown at some point).
(Ignoring the unrelated syntax error in your code. See my comment above for that.)
As far as your snippet goes, your code is valid. The verbosity of the moves is the price you pay for using std::unique_ptr in this manner, and for passing the unique_ptr into the function rather than a reference to the object itself.
I suppose you have your good reasons for wanting some_function to take a std::unique_ptr and, if that's the case, then as far as I can tell you can't really do any better.
If you don't have your good reasons then, well, there's your answer. :)
Hope that helps.
Your problem is that you both take the unique_ptr by reference and return it. It's a unique pointer- you're treating it liked a shared pointer, and you're left with a wasted nullptr value on the stack. If you took it by value or by rvalue reference, you could just call some_function directly, and you don't have to move the result.
std::unique_ptr<T> some_function( std::unique_ptr<T> &&t )
{
// do stuff
return t;
}
vector_of_finalized_Ts.push_back( some_function(std::unique_ptr<T>(new T(...))));

Resources