Rvalue ссылки и дизайн класса

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

class X
{
string internal;

public:
void set_data(const char* s)
{
internal = s;
}
..
..
..
//other stuff

};

Этот класс используется другим модулем, подобным этому:

//another module
{

string configvalue;
X x;

//read configvalue from a file and call set

...
x.set_data(configvalue.c_str());

//use x to do some magic
..
...}

со ссылками rvalue будет лучше предоставить другую функцию-член, например

class X
{
...
...
....
void set_data(string s)
{
internal = std::move(s);
}
};

Это позволит клиентам этого класса использовать семантику перемещения и предотвратить один набор операций выделения / копирования для каждого использования. Это очень сложный пример, но тот же принцип применим ко всем проектам классов, не нарушая парадигму «минимального интерфейса».

Кто-нибудь понимание по этому вопросу высоко ценится?

2

Решение

Да, добавляя string перегрузка, как вы предлагаете, это хорошая идея. Даже без ссылок на rvalue такая перегрузка была бы хорошей идеей. В противном случае, учитывая std::string sДля его использования придется:

x.set_data(s.c_str());

в то время как

x.set_data(s);

гораздо более интуитивно (и даже немного более эффективно) для клиентов X,

В качестве другого варианта вы можете добавить эти две перегрузки:

void set_data(const string& s) {internal = s;}
void set_data(string&& s)      {internal = std::move(s);}

Это примерно эквивалентно той единственной перегрузке, которую вы правильно предложили. У решения с двумя перегрузками есть очень небольшое преимущество в производительности. Решение для одной перегрузки обойдется дополнительно string переместить конструкцию, когда переданный аргумент является xvalue (lvalue, который был приведен с std::move). Но ход конструктор std::string должно быть очень быстро, так что это не должно быть большим делом. Я упоминаю об этом только в духе полного раскрытия.

Если set_data имеет более одного параметра, подход «по стоимости» становится гораздо более привлекательным. Например рассмотрим случай, когда нужно сдать в два strings. Ваш выбор:

Решение 1

void set_data(string s1, string s2);

Решение 2

void set_data(const string&  s1, const string&  s2);
void set_data(      string&& s1, const string&  s2);
void set_data(const string&  s1,       string&& s2);
void set_data(      string&& s1,       string&& s2);

Как вы можете быстро увидеть, Решение 2 плохо масштабируется с количеством параметров.

Наконец, ни в коем случае не пытайтесь применять оба решения к одному и тому же типу:

Не делай этого!

void set_data(string s)        {internal = std::move(s);}
void set_data(const string& s) {internal = s;}
void set_data(string&& s)      {internal = std::move(s);}

Этот набор перегрузок будет неоднозначным. Как и в C ++ 03, следующие две перегрузки неоднозначны:

void set_data(string s)        {internal = std::move(s);}
void set_data(const string& s) {internal = s;}

Никогда не перегружайте значение-значение ссылкой, ни ссылкой на значение, ни ссылкой на значение.

4

Другие решения

Я не вижу причин, чтобы оба void set_data(const char* s) а также void set_data(string s) как часть интерфейса. Это создаст двусмысленность и склонность к побочным эффектам. Более того, вы по-прежнему передаете аргумент по значению в вызове set_data(string s), Вместо этого я бы предложил определить 2 следующих функции:

void set_data(const string &s);
void set_data(string &&s);

Таким образом, вы можете иметь 2 реализации, первая будет глубоко копировать вашу строку, а вторая может украсть внутреннюю часть строки, так как это rvalue (не забудьте оставить его в определенном состоянии, чтобы деструктор мог уничтожить его без проблем — подробности см. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html#Move_Semantics).

Вторая версия будет вызываться автоматически либо на rvalue string аргумент или если аргумент вынужден rvalueнапример, std::move,

Если вы хотите иметь опцию по стоимости, вы можете использовать rvalue версия этого API в сочетании с конструктором копирования строк: set_data(string(str)),

-1

По вопросам рекламы [email protected]