2013-02-23 3 views
3

Этот вопрос (код ниже) std::async and object copy заставил меня задуматься о копировании/перемещении больших реализаций библиотеки. Например, это составляет 5 экземпляров. Контрмеры могут быть сложными, например, в случае async, где передача по ссылке в противоположность значению может вызвать проблемы с параллелизмом. Перемещение конструкторов также не всегда дешево.действительно ли подсчет ходов вызывает эффект Гейзенберга?

Мой вопрос может контрмеры, как найти способ пройти по ссылке действительно решить проблему, которая не существует? Я предполагаю, что большинство, если не все библиотечные функции, окажутся вложенными, они часто представляют собой только одну или две строки кода. Я, конечно, все еще получаю пять «delete obj» на выходе, потому что компилятор должен следовать правилу как будто. Если бы я убрал побочный эффект деструктора, не печатая, как бы правило бы правило, и в итоге получилось бы только одно копирование/перемещение в выпусках?

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

class obj { 
public: 
    int val; 
    obj(int a) : val(a) { 
     cout << "new obj" << endl; 
    } 
    ~obj() { 
     cout << "delete obj" << endl; 
    } 
}; 

void foo(obj a) { 
    this_thread::sleep_for(chrono::milliseconds(500)); 
    cout << a.val << endl; 
} 

int main(int argc, int **args) { 
    obj a(5); 
    auto future = async(foo, a); 
    future.wait(); 
    return 0; 
} 

ответ

5

Учитывает ли счетные движения эффект Гейзенберга?

Нет, не совсем. Если вы имеете в виду, что наблюдение за событием меняет само событие, я считаю, что это неправильная метафора в этом случае.

Риск скорее в том, что ваше наблюдение пропустит мероприятие, как если бы вы никогда не писали эти побочные эффекты. Хотя, вообще, побочные эффекты должны приниматься во внимание компиляторами в соответствии с правилом «как если» (1.9/1), существует несколько важных ситуаций, когда правило «как будто» делает не: Дело в том, что копирование/перемещение эликсира временного объекта может выполняться компилятором.

ситуаций, когда это разрешено точно описано в пункте 12.8/31 C++ 11 стандарта на:

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

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

Важным является то, что ваши побочные эффекты могут быть пропущены. Если реализация std::async() выполняет некоторые копии или перемещения, в зависимости от того, как это делается, компилятор может удалять их, даже если у вас есть распечатки там или, что более важно, даже если у вас есть побочные эффекты.

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

+1

вы преследуете меня или просто типа вопроса, который я задаю;) – odinthenerd

+0

@PorkyBrain: Ничего личного, я обещаю ;-) –

3

Там только должна быть одна копия, которая происходит потому, что вы передаете именующее выражение в std::async, все остальные могут быть шаги, если ваш тип был подвижен, который это не потому, что ваш определенный пользователем деструктор подавляет неявно определенный конструктор перемещения. Вы можете превратить эту копию в ход, выполнив async(foo, std::move(a)), чтобы передать rvalue.

Помните, что если вы видите пять деструкторов один из них является a сам и один является параметром функции foo, так что оставляет еще три сделали внутренне std::async. С GCC есть только еще два, я не думаю, что это можно сделать с меньшим количеством, но на самом деле им тоже не нужно больше. Если тип движется, все внутренние «копии» должны быть перемещены (если только ваша версия async действительно плохо написана)

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

Как объяснено в ответах на ваш другой вопрос, побочные эффекты в вашем деструкторе не мешают копирования Пропуска, что позволено произойти, даже если он устраняет побочные эффекты, поэтому ответ на:

бы как будто правило идет дальше и заканчивается только одним копированием/движением в сборках релизов?

нет, и ответ на:

Есть вещи, которые я должен избегать при написании перемещения конструкторов, чтобы не путать компилятор или непреднамеренно ввести побочные эффекты и остановить его от оптимизации?

также нет. Побочные эффекты не препятствуют перемещению. Перемещение не выполняется оптимизатором, это делается, когда ваш код создает (или назначает) объект из rvalue. Это не оптимизация, она регулируется правилами и семантикой языка C++.

В этом коде:

A a; 
A b = a; 

компилятор не может использовать конструктор для перемещения b, независимо от того, насколько умны его оптимизатор. Он должен использовать конструктор копирования, это то, что говорят правила C++.В этом коде:

A a; 
A b = std::move(a); 

если A имеет конструктор перемещения компилятор не может использовать конструктор копирования для b, он должен использовать конструктор двигаться, даже без оптимизации включена, это то, что правила C++ говорят.

+0

снова разрывается между тем, кто принимает, +1 за очень хороший ответ. – odinthenerd

Смежные вопросы