CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 3 of 3
  1. #1
    Join Date
    Mar 2006
    Posts
    151

    safe to reinterpret_cast vector<CComPtr<>>?

    Hello,

    I am trying to use CComPtr to manage all of the COM objects in a block of code which uses DirectWrite.

    IDWriteFontFace::GetFiles takes an array of pointers to IDWriteFontFile as its second argument. The caller must supply the memory block which will receive the pointers. I want to use std::vector<CComPtr> to manage all of the returned IDWriteFontFile objects. Can I do that as shown in the following code snippet?

    Please note that I'm using static_assert to verify that the memory layout of CComPtr is what I expect. Then reinterpret_cast is used to give GetFiles the pointer type it expects, and that pointer type is what I would effectively expect the guts of the vector object to be.

    The code is post C++11 so CAdapt isn't needed.

    Is this safe and guaranteed to work? If not, is there an alternative method I could use which is better than reverting to raw pointers?


    Code:
                // Query the number of files.
                UINT32 nFiles = 0;
                ThrowIfFailed(ptrFontFace->GetFiles(&nFiles, nullptr));
    
    
                // Allocate storage to hold the files.
                static_assert(sizeof(CComPtr<IDWriteFontFile>) == sizeof(IDWriteFontFile*),
                              "The vector of CComPtr which follows cannot be used safely.");
                std::vector<CComPtr<IDWriteFontFile>> vFontFiles;
                vFontFiles.resize(nFiles);
    
    
                // Retreive the files into the allocated storage.
                ThrowIfFailed(ptrFontFace->GetFiles(&nFiles, reinterpret_cast<IDWriteFontFile**>(vFontFiles.data())));
    Thank you,
    GeoRanger
    Last edited by GeoRanger; January 30th, 2020 at 12:05 AM. Reason: Asked for an alternative idea if the snippet is not safe and guaranteed to work

  2. #2
    Join Date
    Nov 2003
    Location
    Belgium
    Posts
    8,150

    Re: safe to reinterpret_cast vector<CComPtr<>>?

    I don't think this is safe. The elements in your vector are instances of CComPtr, while the GetFiles() method needs a buffer of plain IDWriteFontFile pointers.
    I would create a vector<IDWriteFontFile*>, pass that to GetFiles(), and when the call succeeds, immediately convert this vector<IDWriteFontFile*> to a vector<CComPtr<IDWriteFontFile>> and wrap each raw IDWriteFontFile pointer in a CComPtr.
    Marc Gregoire - NuonSoft (http://www.nuonsoft.com)
    My Blog
    Wallpaper Cycler 3.5.0.97

    Author of Professional C++, 4th Edition by Wiley/Wrox (includes C++17 features)
    ISBN: 978-1-119-42130-6
    [ http://www.facebook.com/professionalcpp ]

  3. #3
    Join Date
    Mar 2006
    Posts
    151

    Re: safe to reinterpret_cast vector<CComPtr<>>?

    Thank you! I'm new to COM so this has been quite a dive. Apparently, one can do the job safely as long as the vector<CComPtr<IDWriteFontFile>> is allocated before the call to GetFiles. One not-readily-apparent issue is when the raw pointer is assigned to the CComPtr, it increments the reference count. So instead of using an assignment (and thus CComPtr's assignment operator), one must use the CComPtr::Attach() function. (This is probably old hat to COM veterans but it's new to me.)

    This is the replacement to the code in my original post:

    Code:
                std::vector<IDWriteFontFile *       > vRawFiles (nFiles);
                std::vector<CComPtr<IDWriteFontFile>> vFontFiles(nFiles);
    
    
                // With both arrays allocated, retreival of the files into the raw pointer array is safe.
                ThrowIfFailed(ptrFontFace->GetFiles(&nFiles, vRawFiles.data()));
    
    
                // Move the files to the array of smart pointers.
                for (UINT32 iFile = 0; iFile < nFiles; ++iFile)
                {
    #               if defined (_DEBUG) && defined(DoubleCheckReferenceCount)
                    // Obtain the reference count to make sure it is correct when the transfer to the
                    // CComPtr pointer is complete.
                    ULONG nReferencesBeginAdd     = vRawFiles[iFile]->AddRef ();
                    ULONG nReferencesBeginRelease = vRawFiles[iFile]->Release();
    #               endif
    
    
                    // Move the COM object to the CComPtr.  Using Attach() avoids incrementing the
                    // reference count.  Using instead CComPtr's assignment operator would increment it.
                    vFontFiles[iFile].Attach(vRawFiles[iFile]);
    
    
    #               if defined (_DEBUG) && defined(DoubleCheckReferenceCount)
                    // Double-check the reference count.
                    ULONG nReferencesEndAdd     = vRawFiles[iFile]->AddRef ();
                    ULONG nReferencesEndRelease = vRawFiles[iFile]->Release();
    
    
                    // Theoretically, these asserts could fire a false alarm if some other process or
                    // thread attached to the COM object between here and the top of this loop, but the
                    // probability is small so a few debug runs with this in place to make sure
                    // everything is correct is worthwhile.
                    assert(nReferencesBeginAdd     == nReferencesEndAdd     );
                    assert(nReferencesBeginRelease == nReferencesEndRelease );
    #               endif
                }
    Thanks again for the help!
    GeoRanger

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured