Передача по ссылке const или использование семантики перемещения [дубликат]

Это должно работать:

box2.appendChild(box1);
522
задан Mateen Ulhaq 20 April 2012 в 01:47
поделиться

11 ответов

Herb Sutter все еще записывается вместе с Bjarne Stroustroup, рекомендуя const std::string& как тип параметра; см. https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rf-in .

В любом из других ответов здесь нет ни малейшей ошибки: если вы передадите строковый литерал в параметр const std::string&, он передаст ссылку на временную строку, созданную на лету для хранения символов буквального. Если вы сохраните эту ссылку, она будет недействительной после освобождения временной строки. Чтобы быть в безопасности, вы должны сохранить копию , а не ссылку. Проблема связана с тем, что строковые литералы - это типы const char[N], для которых требуется продвижение до std::string.

Код ниже иллюстрирует ловушку и обходной путь вместе с небольшим вариантом эффективности - перегрузка с помощью метода const char*, как описано в . Есть ли способ передать строковый литерал как ссылку в C ++ .

(Примечание: Sutter & amp; Stroustroup советует, чтобы, если вы сохраняете копию строки, также предоставляете перегруженную функцию параметром & amp; & amp; и std :: move ( ) it.)

#include <string>
#include <iostream>
class WidgetBadRef {
public:
    WidgetBadRef(const std::string& s) : myStrRef(s)  // copy the reference...
    {}

    const std::string& myStrRef;    // might be a reference to a temporary (oops!)
};

class WidgetSafeCopy {
public:
    WidgetSafeCopy(const std::string& s) : myStrCopy(s)
            // constructor for string references; copy the string
    {std::cout << "const std::string& constructor\n";}

    WidgetSafeCopy(const char* cs) : myStrCopy(cs)
            // constructor for string literals (and char arrays);
            // for minor efficiency only;
            // create the std::string directly from the chars
    {std::cout << "const char * constructor\n";}

    const std::string myStrCopy;    // save a copy, not a reference!
};

int main() {
    WidgetBadRef w1("First string");
    WidgetSafeCopy w2("Second string"); // uses the const char* constructor, no temp string
    WidgetSafeCopy w3(w2.myStrCopy);    // uses the String reference constructor
    std::cout << w1.myStrRef << "\n";   // garbage out
    std::cout << w2.myStrCopy << "\n";  // OK
    std::cout << w3.myStrCopy << "\n";  // OK
}

OUTPUT:

const char * constructor
const std::string& constructor

Second string
Second string
351
ответ дан Community 19 August 2018 в 03:32
поделиться
  • 1
    Интересный момент о том, что конструктор копирования достаточно умен, чтобы не беспокоиться об SSO, если он не использует его. Возможно, правильно, мне нужно будет проверить, правда ли это ;-) – Benj 19 April 2012 в 16:34
  • 2
    std :: string - стандартный класс библиотеки. Он уже перемещается и копируется. Я не вижу, как это уместно. ОП задает больше о производительности перемещения по сравнению с ссылками , а не производительности перемещения и копии. – Nicol Bolas 19 April 2012 в 17:19
  • 3
    Этот ответ подсчитывает количество ходов и копий std :: string будет проходить по схеме с пропуском, описанной как Herb, так и Dave, vs передавая по ссылке пару перегруженных функций. Я использую код OP в демонстрации, за исключением замены в фиктивной строке криком, когда он копируется / перемещается. – Howard Hinnant 19 April 2012 в 17:35
  • 4
    Когда вы говорите, что переход в значение дороже, чем использование ссылок, это все же более дорогостоящим из-за постоянной суммы (независимо от длины перемещаемой строки)? – Neil G 19 April 2012 в 20:42
  • 5
    @NeilG: Вы понимаете, что такое "зависимая от реализации" означает? То, что вы говорите, неверно, потому что оно зависит от , если и как выполняется SSO. – ildjarn 19 April 2012 в 22:50
  • 6
    @ildjarn: В случае анализа, если худший случай чего-то связан константой, то это все равно постоянное время. Нет ли длинной маленькой струны? Разве эта строка не требует определенного количества времени для копирования? Не все ли меньшие строки требуют меньше времени для копирования? Затем строковое копирование для небольших строк является «постоянным временем». в порядке анализа - несмотря на то, что небольшие строки занимают различное количество времени для копирования. Анализ порядка связан с асимптотикой . – Neil G 19 April 2012 в 22:56
  • 7
    @NeilG: Конечно, но ваш исходный вопрос был «, который по-прежнему более дорогой из-за постоянной величины (независимо от длины перемещаемой строки) правильно? & quot; То, что я пытаюсь сделать, это может быть более дорогостоящим из разных постоянных количеств в зависимости от длины строки, которая суммируется как «нет». – ildjarn 19 April 2012 в 22:59
  • 8
    @Benj: Старый комментарий, который я знаю, но если SSO достаточно мало, его копирование безоговорочно происходит быстрее, чем выполнение условной ветви. Например, 64 байта - это строка кэша и может быть скопирована в действительно тривиальный промежуток времени. Вероятно, 8 циклов или меньше на x86_64. – Zan Lynx 15 August 2013 в 19:58
  • 9
    Вероятно, вы должны оптимизировать код перед выполнением тестов ... – The Paramagnetic Croissant 8 December 2014 в 12:42
  • 10
    @TheParamagneticCroissant: У вас были разные результаты? Если это так, используя какой компилятор с аргументами командной строки? – Howard Hinnant 8 December 2014 в 16:18
  • 11
    Почему строка должна быть moved от B до C в случайном случае? Если B является B(std::string b), а C является C(std::string c), то либо мы должны называть C(std::move(b)) в B, либо b должны оставаться неизменными (таким образом, «не отодвинуты от») до выхода B. (Возможно, оптимизирующий компилятор будет перемещать строку под правилом as-if, если b не используется после вызова, но я не думаю, что есть сильная гарантия.) То же самое верно для копии str к m_str. Даже если параметр функции был инициализирован с rvalue, он является значением l внутри функции, и std::move требуется для перехода от этого lvalue. – Pixelchemist 16 July 2015 в 11:04
  • 12
    Это другая проблема, и WidgetBadRef не нуждается в const и amp; параметр должен идти не так. Вопрос в том, что если WidgetSafeCopy просто взял параметр строки, будет ли он медленнее? (Я думаю, что копия, временная для участника, безусловно, легче заметить) – Superfly Jon 10 March 2017 в 11:53
  • 13
    Обратите внимание, что T&& не всегда является универсальной ссылкой; на самом деле, std::string&& всегда будет ссылкой на rvalue и никогда не будет универсальной ссылкой, потому что не выполняется никакого вывода типа . Таким образом, Stroustroup & amp; Совет Саттера не противоречит Мейерсу. – Justin Time 17 April 2017 в 22:12
  • 14
    @JustinTime: спасибо; Я удалил неверное окончательное предложение, требующее, по сути, что std :: string & amp; & amp; будет универсальной ссылкой. – circlepi314 18 April 2017 в 23:04
  • 15
    @ circlepi314 Добро пожаловать. Это легко смешивать, иногда может сбивать с толку, является ли какой-либо данный T&& выведенной универсальной ссылкой или не выводимой ссылкой rvalue; вероятно, было бы яснее, если бы они представили другой символ для универсальных ссылок (например, &&&, как комбинацию & и &&), но это, вероятно, просто выглядело бы глупо. – Justin Time 19 April 2017 в 21:50
  • 16
    Даже если SSO не копируется конструктором копирования, std::string<> - 32 байта, которые выделены из стека, 16 из которых должны быть инициализированы. Сравните это с 8 байтами, выделенными и инициализированными для ссылки: это вдвое больший объем работы ЦП, и он занимает в четыре раза больше пространства кеша, которое не будет доступно для других данных. – cmaster 19 June 2018 в 22:10
  • 17
    О, и я забыл говорить о передаче аргументов функции в регистры; что привело бы использование стека ссылки до нуля для последнего вызова ... – cmaster 19 June 2018 в 22:11
354
ответ дан Community 30 October 2018 в 15:16
поделиться

Если вам действительно нужна копия, все равно разумно принять const &. Например:

bool isprint(std::string const &s) {
    return all_of(begin(s),end(s),(bool(*)(char))isprint);
}

Если вы измените это значение, чтобы взять строку по значению, вы в конечном итоге перемещаете или копируете параметр, и в этом нет необходимости. Скорее всего, не только копирование / перемещение скорее дороже, но и новый потенциальный сбой; копия / перемещение может вызвать исключение (например, распределение во время копирования может завершиться с ошибкой), тогда как ссылка на существующее значение не может быть.

Если вам do нужна копия, тогда передача и возврат по значению обычно (всегда?) лучший вариант. На самом деле я вообще не стал бы беспокоиться об этом в C ++ 03, если вы не обнаружите, что дополнительные копии фактически вызывают проблемы с производительностью. Копирование elision кажется довольно надежным для современных компиляторов. Я думаю, что скептицизм и настойчивость людей в том, что вы должны проверить свою таблицу поддержки компилятора для RVO, в большинстве случаев устарели.


Короче говоря, C ++ 11 ничего не меняет в этом отношении, кроме для людей, которые не доверяли копированию.

41
ответ дан bames53 19 August 2018 в 03:32
поделиться
  • 1
    Перемещение конструкторов обычно реализуется с помощью noexcept, но конструкторы копирования, очевидно, не являются. – leftaroundabout 19 April 2012 в 16:53

Это сильно зависит от реализации компилятора.

Однако это также зависит от того, что вы используете.

Давайте рассмотрим следующие функции:

bool foo1( const std::string v )
{
  return v.empty();
}
bool foo2( const std::string & v )
{
  return v.empty();
}

Эти функции реализованы в отдельном блоке компиляции, чтобы избежать встраивания. Затем: 1. Если вы передадите литерал для этих двух функций, вы не увидите большой разницы в характеристиках. В обоих случаях должен быть создан строковый объект 2. Если вы передадите другой объект std :: string, foo2 превзойдет foo1, потому что foo1 сделает глубокую копию.

Вкл. мой компьютер, используя g ++ 4.6.1, получил следующие результаты:

  • переменная по ссылке: 1000000000 итераций -> время прошло: 2.25912 сек
  • переменная по значению: 1000000000 итераций -> Истекшее время: 27.2259 сек
  • литерал по ссылке: 100000000 итераций -> пройденное время: 9.10319 сек
  • литерал по значению: 100000000 итераций -> время прошло: 8.62659 сек
55
ответ дан BЈовић 19 August 2018 в 03:32
поделиться
  • 1
    Что более важно, так это то, что происходит внутри внутри : , если он вызван с ссылкой, должен сделать внутреннюю копию, которая может быть опущена при передаче по значению ? – leftaroundabout 19 April 2012 в 16:58
  • 2
    @leftaroundabout Да, конечно. Мое предположение, что обе функции выполняют точно то же самое. – BЈовић 19 April 2012 в 17:02
  • 3
    Это не моя мысль. Независимо от того, будет ли проходить по значению или по ссылке, зависит от того, что вы делаете внутри функции. В вашем примере вы фактически не используете большую часть строкового объекта, поэтому ссылка очевидно лучше. Но если задача функции заключалась в том, чтобы поместить строку в какую-либо структуру или выполнить, скажем, какой-то рекурсивный алгоритм, включающий множественные расщепления строки, передача по значению может фактически сохранить некоторое копирование по сравнению с передачей по ссылке , Николь Болас объясняет это довольно хорошо. – leftaroundabout 19 April 2012 в 19:55
  • 4
    Для меня "это зависит от того, что вы делаете внутри функции & quot; плохой дизайн - поскольку вы основываете подпись функции на внутренних элементах реализации. – Hans Olsson 9 December 2016 в 17:48
  • 5
    Возможно, это опечатка, но последние два литеральных тайминга имеют в 10 раз меньше циклов. – TankorSmash 23 February 2017 в 20:20

Почти.

В C ++ 17 мы имеем basic_string_view<?>, что сводит нас к основному узкому варианту использования для параметров std::string const&.

Существование move semantics удалила один прецедент для std::string const& - если вы планируете сохранить параметр, использование std::string по значению более оптимально, так как вы можете move выйти из параметра.

Если кто-то назвал вашу функцию сырым C "string", это означает, что только один std::string буфер когда-либо выделен, в отличие от двух в случае std::string const&.

Однако, если вы этого не сделаете намеревается сделать копию, взятие std::string const& по-прежнему полезна в C ++ 14.

С std::string_view, если вы не передаете указанную строку API, который ожидает C-стиль '\0' -термированные буферы символов, вы можете более эффективно получать функциональные возможности std::string, не рискуя распределением. Необработанную строку C можно даже превратить в std::string_view без какого-либо выделения или копирования символов.

В этот момент использование для std::string const& происходит, когда вы не копируете данные по оптовой торговле и собирается передать его API-интерфейсу C, который ожидает буфер с нулевым завершением, и вам нужны строковые функции более высокого уровня, которые предоставляет std::string. На практике это редкий набор требований.

18
ответ дан Davis Herring 19 August 2018 в 03:32
поделиться

IMO, использующая ссылку C ++ для std::string, представляет собой быструю и короткую локальную оптимизацию, а использование передачи по значению может быть (или нет) лучшей глобальной оптимизацией.

Итак, ответ таков: это зависит от обстоятельств:

  1. Если вы пишете весь код извне во внутренние функции, вы знаете, что делает код, вы можете используйте ссылку const std::string &.
  2. Если вы пишете библиотечный код или используете сильно библиотечный код, в котором переданы строки, вы, вероятно, получите больше в глобальном смысле, доверяя поведению конструктора std::string.
7
ответ дан digital_infinity 19 August 2018 в 03:32
поделиться

Проблема заключается в том, что «const» является неграмотным классификатором. То, что обычно подразумевается под «const string ref», это «не изменять эту строку», а не «не изменять счетчик ссылок». В C ++ просто нет способа сказать , что члены являются «const». Они либо все, либо ни один из них.

Чтобы взломать эту проблему языка, STL может разрешить «C ()» в вашем примере, чтобы в любом случае сделать семантическую копию перемещения , и покорно игнорируют «const» в отношении счетчика ссылок (изменяемый). Пока это было четко указано, все будет хорошо.

Поскольку STL этого не делает, у меня есть версия строки, которая const_casts & lt;> удаляет ссылочный счетчик (без возможности ретроактивно сделать что-то изменчивое в иерархии классов), и - lo and behold - вы можете свободно передавать cmstring в качестве ссылок на const и делать копии их в глубоких функциях в течение всего дня без каких-либо утечек или проблем.

Поскольку C ++ не предлагает «гранулярность производного класса» здесь, написав хорошую спецификацию и создание блестящего нового объекта const constable (cmstring) - лучшее решение, которое я видел.

1
ответ дан Erik Aronesty 19 August 2018 в 03:32
поделиться
  • 1
    Ни в коем случае, кроме ключевого слова mutable ... – Ben Voigt 27 April 2015 в 22:38
  • 2
    @BenVoigt yep ... вместо того, чтобы отбрасывать, он должен быть изменен ... но вы не можете изменить член STL для изменения в производном классе. – Erik Aronesty 10 May 2018 в 20:52

См. «Herb Sutter» Назад к основам! Основы современного стиля C ++ ». Среди других тем он рассматривает передаваемый параметр, который был дан в прошлом, и новые идеи, которые приходят в с C ++ 11 и специально рассматривает идею передачи строк по значению.

slide 24 [/g4]

Тесты показывают, что передача std::string s по значению, в случаях, когда функция будет копировать его в любом случае, может быть значительно медленнее!

Это потому, что вы вынуждаете его всегда делать полную копию (а затем перемещаться на место), а версия const& обновит старую строку, которая может повторно использовать уже выделенный буфер.

См. его слайд 27: Для «заданных» функций опция 1 такая же, как и всегда. Вариант 2 добавляет перегрузку для ссылки rvalue , но это дает комбинаторный взрыв, если имеется несколько параметров.

Только для параметров «sink», где должна быть создана строка (не изменилось ее существующее значение), что трюк с пропуском va lid, то есть конструкторы, в которых параметр непосредственно инициализирует член типа соответствия.

Если вы хотите увидеть, как глубоко вы можете беспокоиться об этом, посмотрите Nicolai Josuttis и удачи с этим ( «Perfect-Done!» n раз после обнаружения ошибки в предыдущей версии. Когда-либо там?)


Это также суммируется как ⧺F.15 в Стандартных правилах.

3
ответ дан JDługosz 19 August 2018 в 03:32
поделиться

Короткий ответ: НЕТ! Длинный ответ:

  • Если вы не будете изменять строку (лечение будет доступно только для чтения), передайте ее как const ref&. (const ref&, очевидно, должно оставаться в пределах область действия, в то время как исполняемая функция выполняет)
  • Если вы планируете изменить ее или знаете, что она выйдет из области видимости (threads) , передайте ее как value, не копируйте const ref& внутри вашего тела функции.

Была запись на cpp-next.com под названием «Требуется скорость, перейдите по значению! «. TL; DR:

Guideline: не копируйте аргументы функции. Вместо этого передайте их по значению и пусть компилятор выполнит копирование.

ПЕРЕВОД ^ ^ / / 10]

Не копируйте аргументы функции --- означает: если вы планируете изменить значение аргумента, скопировав его во внутреннюю переменную, просто используйте аргумент значения вместо .

Итак, не делайте этого:

std::string function(const std::string& aString){
    auto vString(aString);
    vString.clear();
    return vString;
}

выполните следующее:

std::string function(std::string aString){
    aString.clear();
    return aString;
}

Когда вам нужно изменить значение аргумента в своем теле функции.

Вам просто нужно знать, как вы планируете использовать аргумент в теле функции. Только для чтения или NOT ... и если он находится в пределах видимости.

40
ответ дан LearnCocos2D 19 August 2018 в 03:32
поделиться
  • 1
    В некоторых случаях рекомендуется передавать по ссылке, но вы указываете руководство, которое рекомендует всегда передавать по значению. – Keith Thompson 23 August 2013 в 19:53
  • 2
    @KeithThompson Не копируйте аргументы функции. Средства не копируют const ref& во внутреннюю переменную, чтобы изменить ее. Если вам нужно изменить его ... сделайте параметр значением. Это довольно ясно для моего неанглийского языка. – CodeAngry 23 August 2013 в 20:16
  • 3
    @KeithThompson Guideline quote (Не копируйте аргументы функции, а передавайте их по значению и позволяйте компилятору копировать.) COPIED с этой страницы. Если это недостаточно ясно, я не могу помочь. Я не полностью доверяю компиляторам, чтобы сделать лучший выбор. Я предпочел бы быть очень ясно о своих намерениях в том, как я определяю аргументы функции. # 1 Если он доступен только для чтения, это const ref&. # 2 Если мне нужно написать это или я знаю, что он выходит из сферы действия ... Я использую значение. # 3 Если мне нужно изменить исходное значение, я прохожу мимо ref&. # 4 Я использую pointers *, если аргумент не является обязательным, поэтому я могу nullptr его. – CodeAngry 23 August 2013 в 20:39
  • 4
    Я не принимаю сторону на вопрос, следует ли передавать по значению или по ссылке. Я хочу сказать, что в некоторых случаях вы выступаете за передачу ссылок, но затем цитируете (по-видимому, чтобы поддержать свою позицию) руководство, которое рекомендует всегда передавать по значению. Если вы не согласны с руководством, вы можете сказать это и объяснить, почему. (Ссылки на cpp-next.com не работают для меня.) – Keith Thompson 23 August 2013 в 20:53
  • 5
    @KeithThompson: Вы неправильно перефразируете руководство. Это не всегда «всегда». перейдите по значению. Подводя итог, было указано: «Если бы вы сделали локальную копию, используйте pass by value, чтобы компилятор выполнил эту копию для вас. & Quot; Он не говорит, чтобы использовать пропускную стоимость, когда вы не собираетесь делать копию. – Ben Voigt 27 April 2015 в 22:37

Являются ли дни прохождения const std :: string & amp; как параметр над?

Нет. Многие люди берут этот совет (включая Дейва Абрахама) за пределы области, к которой он применим, и упрощают его для применения к всем параметрам std::string - Всегда , проходящему через std::string значение не является «лучшей практикой» для любых произвольных параметров и приложений, поскольку оптимизация этих обсуждений / статей сосредоточена на применении только к ограниченному набору случаев .

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

Как и прежде, передача константой const значительно экономит , когда вы не нужно копировать .

Теперь к конкретному примеру:

Однако inval все еще намного больше размера ссылки (которая обычно реализуется как указатель). Это связано с тем, что std :: string имеет различные компоненты, включая указатель на кучу и член char [] для оптимизации коротких строк. Поэтому мне кажется, что переход по ссылке - это хорошая идея. Может ли кто-нибудь объяснить, почему Herb мог бы это сказать?

Если размер стека является проблемой (и если это не указано / оптимизировано), return_val + inval> return_val - - IOW, использование пикового стека может быть уменьшено , пройдя здесь по значению (обратите внимание: упрощение ABI). Между тем, передача по ссылке const может отключить оптимизацию. Основная причина здесь заключается не в том, чтобы избежать роста стека, а в том, чтобы обеспечить оптимизацию , где это применимо .

Дни прохода по ссылке const не превышают - - правила были сложнее, чем когда-то. Если производительность важна, вам будет разумно рассмотреть, как вы передаете эти типы, на основе сведений, которые вы используете в своих реализациях.

126
ответ дан Lightness Races in Orbit 19 August 2018 в 03:32
поделиться
  • 1
    При использовании стека типичные ABI передают единую ссылку в регистре без использования стека. – ahcox 14 February 2015 в 00:51

Как отмечает @ JDługosz в комментариях, Херб дает другие советы в другом (позже?) разговоре, см. примерно отсюда: https://youtu.be/xnqTKD8uD64?t=54m50s .

Его совет сводится только к использованию параметров значения для функции f, которая принимает так называемые аргументы стока, предполагая, что вы переместите конструкцию из этих аргументов приемника.

Этот общий подход только добавляет накладные расходы конструктора перемещения для аргументов lvalue и rvalue по сравнению с оптимальной реализацией f с учетом значений lvalue и rvalue соответственно. Чтобы понять, почему это так, предположим, что f принимает параметр значения, где T - это некоторая копия и перемещение конструктивного типа:

void f(T x) {
  T y{std::move(x)};
}

Вызов f с аргументом lvalue приведет к конструктор копирования, вызываемый для построения x, и конструктор перемещения, вызываемый для построения y. С другой стороны, вызов f с аргументом rvalue приведет к вызову конструктора перемещения для построения x и другого конструктора перемещения, который будет вызываться для построения y.

В общем, оптимальная реализация f для аргументов lvalue выглядит следующим образом:

void f(const T& x) {
  T y{x};
}

В этом случае для построения y вызывается только один конструктор копирования. Оптимальная реализация f для аргументов rvalue, опять-таки, в общем случае выглядит следующим образом:

void f(T&& x) {
  T y{std::move(x)};
}

В этом случае для построения y вызывается только один конструктор перемещения.

Таким образом, разумный компромисс заключается в том, чтобы взять параметр значения и иметь один дополнительный вызов конструктора для аргументов lvalue или rvalue относительно оптимальной реализации, что также является советом, данным в разговоре Херба.

As @ JDługosz отметил в комментариях, передача по значению имеет смысл только для функций, которые будут строить какой-либо объект из аргумента приемника. Когда у вас есть функция f, которая копирует свой аргумент, подход с поправкой будет иметь дополнительные накладные расходы, чем общий метод pass-by-const-reference. Метод pass-by-value для функции f, сохраняющий копию его параметра, будет иметь следующий вид:

void f(T x) {
  T y{...};
  ...
  y = std::move(x);
}

В этом случае есть построение копии и назначение перемещения для аргумент lvalue и конструкцию перемещения и назначение перемещения для аргумента rvalue. Наиболее оптимальным аргументом для аргумента lvalue является:

void f(const T& x) {
  T y{...};
  ...
  y = x;
}

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

Для аргумента rvalue наиболее оптимальная реализация для f, который сохраняет копию, имеет вид:

void f(T&& x) {
  T y{...};
  ...
  y = std::move(x);
}

Таким образом, в этом случае назначается только перемещение. Передача rvalue в версию f, которая принимает ссылку const, стоит только присваивание вместо назначения перемещения. Так, условно говоря, предпочтительнее вариант f, принимающий const-ссылку в этом случае как общую реализацию.

Итак, в общем случае для наиболее оптимальной реализации вам нужно будет перегрузить или сделать что-то вроде идеальной пересылки, как показано в разговоре. Недостатком является комбинаторный взрыв в количестве требуемых перегрузок, в зависимости от количества параметров для f, если вы решите перегрузить класс значений аргумента. Идеальная пересылка имеет тот недостаток, что f становится функцией шаблона, которая препятствует ее созданию в виртуальном режиме и приводит к значительно более сложному коду, если вы хотите получить его на 100% вправо (см. Разговор для деталей gory).

2
ответ дан Ton van den Heuvel 19 August 2018 в 03:32
поделиться
  • 1
    См. Результаты Herb Sutter в моем новом ответе: сделайте это только при перемещении construct , а не переместите присваивание. – JDługosz 25 April 2018 в 18:34
  • 2
    @ JDługosz, спасибо за указатель на разговор Херба, я просто смотрел его и полностью пересматривал свой ответ. Я не знал о назначении (перемещении). – Ton van den Heuvel 9 May 2018 в 00:21
  • 3
    эта цифра и рекомендации в документе Standard Guidelines , теперь. – JDługosz 9 May 2018 в 01:24
Другие вопросы по тегам:

Похожие вопросы: