Понимание правил выбора в отношении c ++ 11 - PullRequest
4 голосов
/ 14 февраля 2012

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

Учитывая следующее

class NRVCA
{
public:
    NRVCA(int x):
    {}
    NRVCA(const NRVCA & Rhs)
    {}    
    NRVCA& operator=(const NRVCA& dref)
    {}          
};

NVCRA GetATemp()
{       
   return NVCRA(5);
} 

NVCRA GetACopy()
{
   NVCRA ret(5);
   ...
   return ret;  
}

int main()
{ 
    //This call will be elided allays and invoke the single param constructor 
    NVCRA A = GetATemp();
    //This call will be a traditional copy the complier may elide this 
    // if so the work will be done inline 
    NVCRA B = GetACopy();

}

В этом случае семантика перемещения не играет никакой роли, и единственное отличие от C ++ 03 в c ++ 11 состоит в том, что вместо того, чтобы компилятору было разрешено исключать, они обязаны исключаться.

Так Вопрос 1. В каких случаях я гарантирую, что конструктор копирования будет или не будет удален.

Вопрос 2. Есть ли способ заставить компилятор не исключаться.

Вопрос 3. Есть ли логическая причина, по которой я бы не хотел, чтобы компилятор делал это, предполагая, что у вас есть логически согласованные операции копирования.

Вопрос 4. Если я определю конструктор перемещения, перемещение произойдет в тех случаях, когда копия все равно не удаляется. Должно ли это повлиять на мой дизайн занятий.

Ответы [ 3 ]

7 голосов
/ 14 февраля 2012
  1. Удаление копий и перемещений всегда является дополнительной оптимизацией, и стандарт не дает никаких гарантий относительно того, когда это будет сделано.Elision отличается от компилятора, выбирающего перемещение поверх копии.Язык гарантирует, что построение перемещения или назначение перемещения выбраны в соответствии с его обычными правилами разрешения перегрузки.

  2. Некоторые компиляторы предлагают флаг для отключения elision.gcc и clang имеют -fno-elide-constructors.У MSVC нет определенной опции, но отключение оптимизации может избежать некоторых ошибок (но некоторые не могут быть отключены, несмотря на то, что, например, копия в Foo x = 1;)

  3. Iне знаю ни одной причины, чтобы не исключать копирование / перемещение в производственных сборках.

  4. Некоторые люди рекомендовали не полагаться на оптимизацию возвращаемого значения при возврате «тяжелых» классов, посколькуРВО не гарантируется.Лично я только что проверил, что мои компиляторы были хороши в этом, и пошел дальше.Теперь, когда объекты можно перемещать, вам больше не нужно беспокоиться о том, поддерживает ли компилятор такие оптимизации, потому что даже если этого не произойдет, вы все равно будете получать движения вместо копий.

4 голосов
/ 14 февраля 2012

Цитируя стандарт C ++ 11 (12.8 / 31): «При соблюдении определенных критериев реализации разрешено опускать конструкцию копирования / перемещения объекта класса, даже если копия /Конструктор перемещения и / или деструктор для объекта имеют побочные эффекты. ", поэтому:

  1. Исключение копирования не гарантируется.(технически; но производители компиляторов мотивированы на это по маркетинговым причинам)
  2. Это вопрос, специфичный для компилятора.
  3. Технически есть некоторые случаи ( см. здесь ), ноони указывали бы (IMO) на некоторую ошибку в дизайне.
  4. Вы все равно должны предоставить конструктор перемещения (если это возможно эффективно реализовать).В некоторых случаях исключение копирования запрещено, но конструктор перемещения вполне подходит:

    vector<string> reverse(vector<string> vec)
    {
        reverse( vec.begin(), vec.end() );
        return vec;
    }
    
    auto vec = reverse(vector<string>{"abc", "def", "ghi"});
    

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


Чтобы быть более точным в отношении моего последнего замечания, я цитирую N3290, который трудно получить в настоящее время, но он очень близок к N3337 :

12.8 / 31:

При выполнении определенных критериев реализация может опустить конструкцию копирования / перемещения объекта класса, даже если копирование / перемещениеКонструктор и / или деструктор для объекта имеют побочные эффекты.В таких случаях реализация рассматривает источник и цель пропущенной операции копирования / перемещения просто как два разных способа обращения к одному и тому же объекту, и уничтожение этого объекта происходит в более поздние времена, когда два объекта были быуничтожен без оптимизации.Такое исключение операций копирования / перемещения, называемое разрешением копирования, допускается в следующих обстоятельствах (которые могут быть объединены для удаления нескольких копий):

- в операторе возврата в функции с типом возврата класса,если выражение является именем энергонезависимого автоматического объекта (, отличного от функции или параметра предложения catch ) с тем же типом cv-unqualified, что и тип возвращаемого функцией, операция копирования / перемещения может бытьопускается при построении автоматического объекта непосредственно в возвращаемое значение функции

12,8 / 32:

Когда критерии для исключения операции копирования будут выполнены или будетвстречаются, за исключением того факта, что исходный объект является параметром функции, и копируемый объект обозначается lvalue, разрешение перегрузки для выбора конструктора для копии сначала выполняется так, как если бы объект был обозначенRvalue.Если не удается разрешить перегрузку или если тип первого параметра выбранного конструктора не является rvalue-ссылкой на тип объекта (возможно, cv-квалифицированный), разрешение перегрузки выполняется снова, рассматривая объект как lvalue.[...]

2 голосов
/ 14 февраля 2012
  1. Я не верю, что есть какие-либо гарантии относительно того, когда компилятор решит удалить копию, даже если у конструктора копирования есть побочные эффекты.Это явно разрешено стандартом.

  2. Какой компилятор?Например, я считаю , что вы можете отключить оптимизацию и не получить права на g ++.* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * В этом языке нет никакого способа заставить любой компилятор сгенерировать конструктор копирования там, где он считает возможным удаление.Стандарт явно разрешает исключение, даже если у конструкторов копирования есть побочные эффекты.

  3. Я не могу придумать причину, чтобы не исключать.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...