Неконстантная функция возврата ссылки используется как r-значение по сравнению с функцией возврата значения const - PullRequest
1 голос
/ 12 октября 2019

У меня есть две версии функции. Один возвращает по значению, предназначенному для использования в качестве r-значения. Другой возвращает по ссылке, предназначенный для использования в качестве l-значения (для записи в вектор audio_data).

float AudioData::sample(unsigned frame, unsigned channel) const
{
    return audio_data[frame * channel_count + channel];
}

float& AudioData::sample(unsigned frame, unsigned channel)
{
    clearSplits(); // Clear out cached information that may be invalidated by this call
    return audio_data[frame * channel_count + channel];
}

Во время отладки я заметил, что переопределение возврата ссылки используется какr-значение:

const float *AudioData::split(unsigned channel)
{
    if (splits[channel] != nullptr) return splits[channel];
    if (channel_count == 1) return data();

    float *split = new float[frame_count];

    for (unsigned i = 0; i < frame_count; ++i)
    {
        split[i] = sample(i, channel); // Calls the reference-returning override
    }

    splits[channel] = split;
    return split;
}
void AudioData::clearSplits() // This gets called while writing to the splits!
{
    for (unsigned i = 0; i < splits.size(); ++i)
    {
        if (splits[i] != nullptr) delete[] splits[i];
        splits[i] = nullptr;
    }
}

Почему компилятор предпочитает использовать неконстантное переопределение l-значения, когда он не изменяет ссылку возврата, и как я могу предотвратить это?

1 Ответ

1 голос
/ 12 октября 2019

Разрешение перегрузки не заботится о типе возврата вашей функции. Все, что его волнует, это типы аргументов для вызова. И в вашем случае, так как вы вызываете sample из split (функция, которая не является константной), неявный аргумент объекта (this) не является константной. По этой причине вызывается неконстантная перегрузка, и она возвращает ссылку.

Простое решение - предоставить другую функцию с другим именем, которая также возвращает копию.

float AudioData::csample(unsigned frame, unsigned channel) const
{
    return sample(fram, channel); // will always call the const overload
}

Если вы против этого, то вы всегда можете const_cast назвать правильный перегруз:

split[i] = const_cast<AudioData const *>(this)->sample(i, channel);
...