I have the following piece of code from Frank Luna's DX12 book:
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
ThrowIfFailed(md3dDevice->CreateCommandQueue(
&queueDesc, IID_PPV_ARGS(&mCommandQueue)));
ThrowIfFailed(md3dDevice->CreateCommandAllocator(
D3D12_COMMAND_LIST_TYPE_DIRECT,
IID_PPV_ARGS(mDirectCmdListAlloc.GetAddressOf())));
ThrowIfFailed(md3dDevice->CreateCommandList(
0,
D3D12_COMMAND_LIST_TYPE_DIRECT,
mDirectCmdListAlloc.Get(), // Associated command allocator
nullptr, // Initial PipelineStateObject
IID_PPV_ARGS(mCommandList.GetAddressOf())));
// Start off in a closed state. This is because the first time we
// refer to the command list we will Reset it, and it needs to be
// closed before calling Reset.
mCommandList->Close();
What I'm wondering is why does he use the & operator when passing the Queue ComPtr but uses the GetAddressOf method for the other two?
With
Microsoft::WRL::ComPtrI prefer the use ofReleaseAndGetAddressOfandGetAddressOfrather than using theoperator&overload. There's a few reasons for this.The older ATL CComPtr when using
operator&is equivalent toGetAdddressOfwith an assert to assume it was nullptr to being with. The WRL ComPtr usesReleaseAndGetAddressOfwhich is the safer default to avoid potential resource leaks, but can also cause confusion when you can end up with 'nullptr' results when you didn't expect it such as trying to pass a pointer-to-a-pointer often used in Direct3D APIs.This design point was driven by a common pattern in all COM code:
With ATL CComPtr, this only works if
ifactoryis in fact nullptr (always true for a local variable but not necessarily for global or class member variables). The WRL ComPtr will always check for non-null and release it if needed, which is more robust but may be unnecessary as in the case of a local variable.The choice, however, makes for problems for Direct3D usage of COM interfaces. For example, the following code is NOT going to work correctly with WRL ComPtr (the RTV will be cleared before you try to set it) and will assert with ATL's CComPtr in DEBUG builds.
You can get it to work as:
But it's probably even clearer to the future reader to do:
In the code snippet from Luna above, it's a safer choice to use
.ReleaseAndGetAddressOfsince the method being called is a creation fucntion and the member variable could already be set. This would avoid memory leaks even when the class is 'misused. I prefer to use.GetAddressOfif I'm initializing a local variable that I know was just created so it's always nullptr.See this wiki page for more advice.