0

I have a pointer to a pointer to an object that will not be mutated, so I thought making the whole chain const would help prevent me from accidentally making changes the the object. const IMMDeviceCollection* const* const ppMMDeviceCollection When I try to call the methods I need, the compiler says it cannot convert a const object to a reference on this line (*ppMMDeviceCollection)->GetCount(&nMMDevices);

Here is what I am doing:

HRESULT getAudioEndpointSpeakerIndices(const IMMDeviceCollection* const* const ppMMDeviceCollection,
                                       std::vector<int> iSpeakers) {
    HRESULT hr;
    UINT nMMDevices;
    IMMDevice* pMMDevice = NULL;
    IPropertyStore* pPropertyStore = NULL;
    PROPVARIANT property;
    // Initialize container for property value.
    PropVariantInit(&property);
    hr = (*ppMMDeviceCollection)->GetCount(&nMMDevices);
    if(hr != S_OK) { goto EXITGAES; }
    for(ULONG i = 0; i < nMMDevices; i++) {
        hr = (*ppMMDeviceCollection)->Item(i, &pMMDevice);
        if(hr != S_OK) { goto EXITGAES; }
        hr = pMMDevice->OpenPropertyStore(STGM_READ, &pPropertyStore);
        if(hr != S_OK) { goto EXITGAES; }
        hr = pPropertyStore->GetValue(PKEY_AudioEndpoint_FormFactor, &property);
        if(hr != S_OK) { goto EXITGAES; }
        if(property.uintVal == Speakers) {
            iSpeakers.push_back(i);
        }
    }
EXITGAES:
    SAFE_RELEASE(pMMDevice);
    SAFE_RELEASE(pPropertyStore);
    return hr;
}

If I remove the const from the pointer to the pointer, the code runs fine. IMMDeviceCollection* const* const ppMMDeviceCollection

Why is this legal, but the above not?

Is there some way to call functions from a const IMMDeviceCollection* const* const ppMMDeviceCollection?

John Glen
  • 771
  • 7
  • 24
  • 2
    [`IMMDeviceCollection::GetCount`](https://learn.microsoft.com/en-us/windows/win32/api/mmdeviceapi/nf-mmdeviceapi-immdevicecollection-getcount) is not declared `const`. – dxiv Dec 12 '20 at 01:10
  • Oh, I mixed up what was const – John Glen Dec 12 '20 at 01:22
  • 1
    Actually, there is no good reason in this case to pass a double pointer as argument, since it is dereferenced `(*ppMMDeviceCollection)` every time it is used, anyway. The first argument can just as well be simply `IMMDeviceCollection *pMMDeviceCollection`. – dxiv Dec 12 '20 at 01:23
  • On the other hand `std::vector iSpeakers` is passed by value, so any updates like `iSpeakers.push_back(i);` will be made on the *copy* received as an argument. If the intention is for the caller to receive the updates back, then `iSpeakers` should be passed by reference, instead. – dxiv Dec 12 '20 at 01:30
  • 1
    Thank you. My Java habits are hard to break even after reading about how c++ works. – John Glen Dec 12 '20 at 01:47
  • *"If I remove the const from the pointer to the pointer,"* -- this is not what you demonstrated via code. You demonstrated removing the const from the object, not from the pointer to the pointer. – JaMiT Dec 12 '20 at 02:07
  • It's impossible for us to answer this without seeing the declaration of `GetCount`. – Tumbleweed53 Dec 12 '20 at 03:32
  • @Tumbleweed53 @dxiv *did* post the declaration of `GetCount`, and the answer is that it's not `const`-qualified (it's `SomeType GetCount();` and not `SomeType GetCount() const;`) and therefore can't be called on a `const` reference... I expected this question to have been closed as a duplicate by now, honestly. @OP: you can't make it `const` because MS designed the API in such a way that it just doesn't work (maybe some implementations of the interface mutate themselves on `GetCount`? oversight?). See the duplicate I just linked for an explanation of how C++ decides whether it should work. – HTNW Dec 12 '20 at 06:08

0 Answers0