ฉันสามารถใช้ std :: transform แบบแทนที่ด้วยนโยบายการดำเนินการแบบขนานได้หรือไม่


11

ถ้าฉันไม่ผิดฉันสามารถทำให้std::transformการดำเนินการในสถานที่ โดยใช้ช่วงเดียวกับ input และ output iterator สมมติว่าฉันมีstd::vectorวัตถุvecแล้วฉันจะเขียน

std::transform(vec.cbegin(),vec.cend(),vec.begin(),unary_op)

unary_opโดยใช้การดำเนินการที่เหมาะสมเอก

ด้วยการใช้มาตรฐาน C ++ 17 ฉันต้องการดำเนินการแปลงแบบขนานโดยการใส่std::execution::parเข้าไปในนั้นเป็นอาร์กิวเมนต์แรก นี้จะทำให้ฟังก์ชั่นการเดินทางจากการโอเวอร์โหลด (1) (2) ในบทความ cppreference std::transformบน อย่างไรก็ตามความคิดเห็นที่เกินพิกัดนี้พูดว่า:

unary_op[... ] ต้องไม่ทำให้ตัววนซ้ำใด ๆ รวมถึงตัววนซ้ำสิ้นสุดหรือแก้ไของค์ประกอบใด ๆ ของช่วงที่เกี่ยวข้อง (ตั้งแต่ C ++ 11)

"แก้ไของค์ประกอบใด ๆ " จริงๆหมายถึงฉันไม่สามารถใช้อัลกอริทึมในสถานที่หรือกำลังพูดถึงรายละเอียดที่แตกต่างที่ฉันตีความผิด?

คำตอบ:


4

หากต้องการอ้างอิงมาตรฐานที่นี่

[alg.transform.1]

op [... ] จะต้องไม่ทำให้ iterator หรือ subranges เป็นโมฆะหรือแก้ไของค์ประกอบในช่วง

สิ่งนี้ห้ามไม่ให้คุณunary_opแก้ไขค่าที่กำหนดเป็นอาร์กิวเมนต์หรือคอนเทนเนอร์เอง

auto unary_op = [](auto& value) 
{ 
    value = 10;    // this is bad
    return value;
}

auto unary_op = [&vec](auto const& value) 
{ 
    vec[0] = value;   // also bad
    return value;
}

auto unary_op = [&vec](auto& value) 
{ 
    vec.erase(vec.begin());   // nope 
    return value;
}

อย่างไรก็ตาม follwing ก็โอเค

auto unary_op = [](auto& value)  // const/ref not strictly needed
{         
    return value + 10;   // totally fine
}

auto unary_op = [&vec](auto& value)
{         
    return value + vec[0];   // ok in sequential but not in parallel execution
}

เป็นอิสระจากUnaryOperationเราได้

[alg.transform.5]

ผลลัพธ์อาจเท่ากับก่อนในกรณีที่การแปลงแบบ unary [... ]

ความหมายการดำเนินงานในสถานที่ได้รับอนุญาตอย่างชัดเจน

ตอนนี้

[algorithms.parallel.overloads.2]

เว้นเสียแต่ว่าจะระบุเป็นอย่างอื่นซีแมนทิกส์ของ ExecutionPolicy อัลกอริทึมโหลดจะเหมือนกับโอเวอร์โหลดที่ไม่มี

หมายความว่านโยบายการดำเนินการไม่มีความแตกต่างที่ผู้ใช้มองเห็นในอัลกอริทึม คุณสามารถคาดหวังว่าอัลกอริทึมจะให้ผลลัพธ์ที่แน่นอนเหมือนกับว่าคุณไม่ได้ระบุนโยบายการดำเนินการ


6

ฉันเชื่อว่ามันพูดถึงรายละเอียดที่แตกต่าง unary_opต้องใช้องค์ประกอบของลำดับและส่งกลับค่า ค่านั้นจะถูกจัดเก็บ (โดยtransform) ลงในลำดับปลายทาง

ดังนั้นนี่unary_opจะดี:

int times2(int v) { return 2*v; }

แต่อันนี้จะไม่:

int times2(int &v) { return v*=2; }

แต่นั่นไม่ใช่สิ่งที่คุณถาม คุณต้องการทราบว่าคุณสามารถใช้unary_opเวอร์ชันของtransformอัลกอริทึมแบบขนานกับช่วงต้นทางและปลายทางเดียวกันได้หรือไม่ ฉันไม่เห็นว่าทำไม transformแมปองค์ประกอบเดียวของลำดับที่มากับองค์ประกอบเดียวของลำดับปลายทาง อย่างไรก็ตามหากคุณunary_opไม่ได้แยกจากกันจริงๆ (กล่าวคือมันอ้างอิงองค์ประกอบอื่น ๆ ตามลำดับ - แม้ว่าจะอ่านได้เท่านั้นคุณก็จะมีการแข่งขันของข้อมูล)


1

ดังที่คุณเห็นในตัวอย่างของลิงก์ที่คุณอ้างถึงการแก้ไของค์ประกอบใด ๆไม่ได้หมายความว่าการแก้ไขทุกประเภทในองค์ประกอบ:

ลายเซ็นของฟังก์ชันควรเท่ากับสิ่งต่อไปนี้:

Ret fun(const Type &a);

ซึ่งรวมถึงการดัดแปลงองค์ประกอบ ในกรณีที่เลวร้ายที่สุดถ้าคุณใช้ iterator เหมือนกันสำหรับปลายทางการแก้ไขควรจะไม่ได้เป็นสาเหตุของการทำให้ iterators ที่เป็นเช่นpush_backเวกเตอร์หรือerasไอเอ็นจีจากvectorซึ่งอาจจะทำให้เกิดความเป็นโมฆะของ iterators

ดูตัวอย่างของความล้มเหลวที่คุณไม่ควรทำสด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.