Is there any reason or convention for not passing COM objects as references to internal functions?
I know that references cannot be used in COM API since that would break binary compatibility. But what about within a module?
It's perfectly OK to pass COM objects by reference to non-COM functions. Even though a reference is just an alias to an object they are typically implemented as pointers under the hood.
The question is fishy, the distinction between objects and interfaces is important in COM. Client code that uses a COM server only ever works with interface pointers. CoCreateInstance() creates an object on the server and returns an interface pointer to one of the interfaces implemented by the coclass. Like IUnknown*. At no point are you ever handling an object. Boilerplate is to leave interface pointers as just pointers and passing them by reference isn't very useful. You could wrap them in a smart pointer class so the Release() call is automatic. Passing that smart pointer object by reference is fine, it doesn't have anything to do with COM.
It could be different in a COM server. You typically implement an object there with a C++ class that implements the COM interfaces. If code in that server needs a reference to that object then it makes sense to just pass a reference to the C++ object. That's just standard usage of references in C++ and doesn't have anything to do with COM.
Related
I was looking at the C++ API of Apache's Arrow library, and noticed that it is littered with member functions that take arguments of type std::shared_ptr<T>*. To me this looks unnecessarily contrived and possibly brittle, and it is frankly strange to me that a library would prescribe how I choose to solve the ownership of my instances of its classes. Thus my conclusion is that there must be some advantages to this approach that I am not aware of, which sparked my curiosity.
What are the advantages of functions that take pointers to smart pointers as arguments?
Herb Sutter does not mention this option in his article on Smart Pointer Parameters.
std::shared_ptr<…>* is used in Arrow when a function is returning an object as a shared_ptr while at the same time the function may fail with one of arrow::Status codes.
Apache Arrow C++ adheres to the Google C++ style guide. One of the aspects is to not use exceptions. Furthermore, normally output will be done with a normal return statement but in the cases where we also need to return a Status, we use the alternative approach of returning it via a non-const pointer.
For inputs where Arrow takes no ownership of the passed parameter, instead of std::shared_ptr<T>, functions take const T&. Shared pointers only appear in function signature if ownership is shared afterwards or when the parameter is an output parameter.
When working with object references in JNI, I can use NewLocalRef to (as the name implies) get a new local reference to the same object.
This is useful when implementing a wrapper in C++. The copy-constructor can invoke NewLocalRef and both instances of the class' destructors can simply use DeleteLocalRef on their own local reference.
I'm also wrapping Java classes using a similar pattern, but calling NewLocalRef with a jclass seems to result in extremely strange (possibly undefined) behaviour.
Is there a way of achieving this using JNI built in functionality, or do I need to write my own reference counter?
It is fairly often suggested not to use raw pointers in modern C++, except for a few rare cases. What is the common practice of using smart pointers in C++ library APIs?
The following use cases come up to my mind:
A function which returns a new object.
A function which returns a new object, but it has also created another reference to this object.
A function which only uses an object it receives as an argument.
A function which takes over the ownership of an object.
A function which will store a reference to an object which it has received as an argument, but there might be other references to the very same object (from the callers side).
Unfortunately, a library API design goes far beyond the rule of the language itself: suddenly you have to care about implementations details such as the ABI.
Contrary to C, where common implementations can easily interact together, C++ implementations have very different ABIs (Microsoft ABI for VC++ is completely incompatible with the Itanium ABI used by gcc and Clang), and C++ Standard Library implementations are also incompatible with each others, so that a library compiled with libstdc++ (bundled with gcc) cannot be used by a program using another major version of libstdc++ or another implementation such as libc++ (bundled with Clang) if std:: classes appear in the interface.
Therefore, it really depends on whether you intend your library to be delivered as a binary or assume the user will be in a position to compile the library with its own compiler and Standard Library implementation of choice. Only in the latter case should you expose a C++ interface, for binary distributions sticking to C is better (and it's also easier to integrate with other languages).
With that out of the way, let's assume you decided to use a C++ API:
1) A function which returns a new object.
If the object can be returned by value, do so; if it is polymorphic, use std::unique_ptr<Object>.
2) A function which returns a new object, but it has also created another reference to this object.
Rare Case. I suppose that you mean it has kept a reference, somehow. In this case you have shared ownership so the obvious choice is std::shared_ptr<Object>.
3) A function which only uses an object it receives as an argument.
Much more complex than it first seems, even supposing no reference to the object is kept.
in general, pass by reference (const or not)
unless you intend to operate on a copy of the object, in which case pass by value to benefit from a potential move
4) A function which takes over the ownership of an object.
Simple ownership: std::unique_ptr<Object>.
5) A function which will store a reference to an object which it has received as an argument, but there might be other references to the very same object (from the callers side).
Shared ownership: std::shared_ptr<Object>
Unique pointers may do the job in the general case.
std::unique_ptr<Foo> func();
So that you can assign them directly to auto variables at the callers site, and not worry about memory management.
auto u = func();
In case you need shared ownership, you can convert smart pointers on the callers site:
std::shared_ptr<Foo> s{func()};
However, in case the return type of the function is not polymorphic, and that type is fast to move, you may prefer return by value:
Foo func();
Shared pointers.
std::shared_ptr<Foo> func();
Simply use a reference or const reference to the object, with raw pointers or smart pointers "dereferenced" at the callers site.
void func(Foo& obj);
void func(const Foo& obj);
In case the parameters are optional, you may use raw pointers, so that you can easily pass a nullptr to them.
void func(Foo *obj);
void func(const Foo *obj);
Unique pointers.
void func(std::unique_ptr<Foo> obj);
Const reference to shared pointers.
void func(const std::shared_ptr<Foo>& obj);
The const reference (to shared pointer) is simply an optimization to prevent adjusting the reference count when the function is called and when it returns.
This is a very old question but also an important one.
One school of thought missing from the answers is that you should not return raw nor smart pointers from your API if you can help it.
The raw pointer issue has been discussed. But smart pointers can also be misused, especially in larger projects with complex internal APIs.
A workaround is creating an RAII/wrapper object that holds the ( never-exposed ) smart pointer.
I don't really understand the difference between a shared_ptr and the new handle notation (^) in C++/CX. From what I've read they seem to do the same thing regarding reference counting and memory management. What am I missing?
std::shared_ptr<Type>
//vs
Type^
Solely considering lifetime management, these are the same: a shared_ptr<T> holds a strong (owning) reference to a T object; a T^ does the same. make_shared<T> is roughly equivalent to ref new T in C++/CX.
If everywhere you see a T^ you think shared_ptr<T> or ComPtr<T> or CComPtr<T>, then that's okay--the lifetime management is roughly the same.
How lifetime management works under the hood is different, though: every T type for which T^ is well-formed is a Windows Runtime reference type that implements the IUnknown interface, so the T object is internally reference counted(*). shared_ptr<T> supports arbitrary types and uses external reference counting (i.e., it allocates its own reference counting mechanism to control the lifetime of the object).
For weak references, shared_ptr<T> has weak_ptr<T>, and T^ has WeakReference. WeakReference is not strongly-typed, but you can easily write a strongly-typed reference wrapper around it. Otherwise, weak references work as you would expect them to. Support for weak references is optional: not all reference types support weak references, but most do.
(*) There is one exception: Platform::String^, which is not a Windows Runtime reference type, but is handled specially for a variety of reasons. You can think of it as being the same as any other T^ with respect to lifetime management, though.
So, why do Windows Runtime types wear hats in C++/CX? Why isn't a library solution like shared_ptr<T> or ComPtr<T> used?
It's because you never really have a pointer (or a hat) to a concrete runtime type: you can only interact with an object via a pointer to one of the interfaces that its type implements. Windows Runtime also does not support interface or class inheritance: every interface must derive directly from IInspectable, and class inheritance is emulated through the use of COM aggregation.
In short, there's no library solution that would result in natural looking C++ code with static type safety. Function calls, derived-to-base conversions, and interface conversions usually require a call to QueryInterface to get the right interface pointer.
You can do this with a library solution (see, for example, the WRL library, or pretty much any COM code), but you can't support C++ language features like implicit conversions or dynamic_cast. Without the hats, you're stuck dealing solely with interface pointers and having to call QueryInterface yourself.
(If you're interested in the rationale behind why the C++/CX language extension were developed and how the C++/CLI syntax ended up being selected for reuse, I'd recommend Jim Springfield's post on this blog from last year, "Inside the C++/CX Design". Also of note is episode 3 of GoingNative, in which Marian Luparu discusses C++/CX.)
As far as I can tell, the latter lacks support for weak references and custom deallocation functions.
Note that the former, being more general, accepts any type (in principle), and for safety and cleanliness calls for the use of the helper function make_shared. The latter is supported at a language level. That means code like this is safe in C++/CX:
some_function(ref new foo(), ref new bar());
While in C++, you need to do this:
// bad: if foo is allocated but bar's allocation throws, you leak!
some_function(new foo(), new bar());
// good: both never make it anywhere but into a shared_ptr, no leaks
some_function(make_shared<foo>(), make_shared<bar>());
Other than that, sure, they implement the same concept. If you're in C++/CX land, use the latter syntax for simplicity and uniformity; if you're trying to stick to standard C++, or are wrapping an existing resource management scheme into a reference-counted scheme, then you'll want the former.
Modern ATL/MFC applications now have access to a new shared pointer class called CAutoPtr, and associated containers (CAutoPtrArray, CAutoPtrList, etc.).
Does the CAutoPtr class implement reference counting?
Having checked the CAutoPtr source, no, reference counting is not supported. Using boost::shared_ptr instead if this ability is required.
The documentation for http://msdn.microsoft.com/en-us/library/txda4x5t(VS.80).aspx
From reading this it looks like it tries to provides the same functionality as std::auto_ptr i.e. It uses ownership semantics. Only one CAutoPtr object holds the pointer and assignment transfers ownership from one CAutoPtr object to another.