Устранение перегрузок без прерывания работы клиентов - PullRequest
0 голосов
/ 12 марта 2020

Вот игрушечный пример того, над чем я сейчас работаю

class Foo
{
   private:
     std::string s;
     std::vector<std::string> v;
   public:

      // Foo constructors and other big 3

      std::string const& strmember() const;
      std::vector<std::string> const& vecmember() const;
      std::vector<std::string>& vecmember();
};

Все хорошо до этого момента. Требование заключается в том, что мне нужно добавить перегрузки и изменить внутренности Foo, как показано ниже

class Foo
{
   private:
     std::u16string ssname;
     std::vector<std::u16string> vvname;
   public:

      // Foo constructors and other big 3

      std::string const& strmember() const;
      std::vector<std::string> const& vecmember() const;
      std::vector<std::string>& vecmember();

      std::u16string const& strmember(int) const;
      std::vector<std::u16string> const& vecmember(int) const;
      std::vector<std::u16string>& vecmember(int);
};

Я должен сохранить старые элементы и добавить перегрузки для новых, чтобы старые клиенты не ломались. Соответствующие преобразования символов выполняются таким образом, что старые конструкторы делегируются новым, а предоставленные элементы изменяются в соответствии с новым дизайном.

При реализации этих элементов, как показано ниже

std::string const& Foo::strmember() const
{
    const auto& name = char_convert(ssname);
    return name; 
}
std::vector<std::string>& Foo::vecmember()
{
    return vecmember();
} 
std::vector<std::string>& Foo::vecmember()
{
    std::vector<std::string> result;
    std::transform(vvname.begin(),vvname.end(),std::back_inserter(result),[] (const std:u16string& in) -> std::string
                                                            {
                                                                return char_convert(in);
                                                            });
    return result;
}

std::u16string const& Foo::strmember(int) const
{
    return ssname;
}

std::vector<std::u16string> const& Foo::vecmember(int) const
{
    return vvname;
}

std::vector<std::u16string>& Foo::vecmember(int)
{
    return vvname;
}

Когда я пытался чтобы скомпилировать измененный код, компилятор выдает мне следующее предупреждение cum error

error: reference to local variable ‘result’ returned [-Werror=return-local-addr]
     std::vector<std::string> result;
                              ^~~~~~
foo.cpp: In member function ‘const string& foo::strmember() const’:
foo.cpp: error: function returns address of local variable [-Werror=return-local-addr]
     return name;
            ^~~~
foo.cpp: note: declared here
     const auto& name = char_convert(ssname);
                                                 ^
cc1plus: all warnings being treated as errors

Как мне решить эту проблему? Я не могу изменить интерфейс, так как это может нарушить юнит-тесты и клиентов.

Как предоставить версию мутатора и средства доступа функций vecmember() и strmember()?

1 Ответ

2 голосов
/ 12 марта 2020

Переменные, локальные для функции, уничтожаются, когда функция выходит из области видимости. Возврат ссылки на такую ​​переменную является неопределенным поведением (ссылка возвращается, когда функция возвращается).

Я хочу выделить еще одну проблему того же типа. Когда вы пишете:

const auto& name = char_convert(ssname); // Bad (undefined behaviour)

Вы связываете ссылку на значение. Временный std::string, возвращаемый char_convert(), будет уничтожен после этого оператора. Так что name болтается даже до того, как возвращается функцией strmember(). Вы, вероятно, должны написать вместо этого (скопировать инициализацию):

auto name = char_convert(ssname); // Better

Теперь, если вы не хотите нарушать совместимость, я думаю, вам нужно будет использовать прокси-класс (как предложено @ Fureei sh) для обработки преобразований под капотом. Здесь вы можете увидеть пример того, как написать прокси-класс (при необходимости).


РЕДАКТИРОВАТЬ:

Как отмечалось в комментариях @ Jarod42 , const auto& name = char_convert(ssame); действительно правильно, потому что, когда временный объект связан со ссылкой, его время жизни будет продлено до самого времени жизни ссылки (до тех пор, пока name не выйдет из область действия в нашем случае).

Но имейте в виду, что name относится не к ssname, а к временному, возвращаемому char_convert(ssname) (так что это синтаксически правильно, но все равно не делает то, что вы хотел это сделать).

В любом случае неопределенное поведение все равно будет происходить после того, как функция вернется

...