Skip to content

Commit becc8e4

Browse files
committed
fix(dslings): 04-rvalue-references 练习侧同步修复,并给 e2e 加脏树防护
上一次提交只带上了 solutions/ 侧 —— 练习侧的补丁被 e2e.sh 的清理钩子 还原掉了,我没复查就提交了。 清理钩子会把参考答案覆盖到练习上再还原,所以它天然会吃掉练习目录里未提交 的改动。这个陷阱已经咬过两次(一次丢了脚手架,一次丢了刚修好的练习), 所以加一道前置检查:练习目录不干净就拒绝运行,并列出是哪些文件。 宁可拒绝,也不能悄悄丢掉别人的工作。
1 parent c9bb1ee commit becc8e4

3 files changed

Lines changed: 35 additions & 6 deletions

File tree

d2x/buildtools/mcpp/tests/e2e.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ restore() {
2424
[ -e "$d" ] && git checkout -- "$d" 2>/dev/null || true
2525
done
2626
}
27+
28+
# 本脚本会把参考答案覆盖到练习上再还原,所以运行前练习必须是干净的 ——
29+
# 否则未提交的改动会被 restore 悄悄丢掉(作者踩过两次:一次丢了脚手架,
30+
# 一次丢了刚修好的练习)。宁可拒绝运行,也不能吃掉别人的工作。
31+
if ! git diff --quiet -- "${EXERCISE_DIRS[@]}" 2>/dev/null; then
32+
echo "拒绝运行:练习目录有未提交的改动,本测试会在结束时还原它们。"
33+
echo "请先提交或 stash:"
34+
git diff --stat -- "${EXERCISE_DIRS[@]}" | sed 's/^/ /'
35+
exit 2
36+
fi
37+
2738
trap restore EXIT
2839

2940
outcome_of() { # $1 = exercise id

dslings/cpp11/04-rvalue-references.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
struct Object;
2323
static Object * object_address = nullptr;
24+
static int move_ctor_calls = 0; // 移动构造被调用的次数, 供断言检查
2425

2526
struct Object {
2627
int data = 0;
@@ -29,16 +30,21 @@ struct Object {
2930
object_address = this;
3031
}
3132
Object(const Object&) { std::cout << "Object(const Object&):" << this << std::endl; }
32-
Object(Object&&) { std::cout << "Object(Object&&):" << this << std::endl; }
33+
Object(Object&&) { ++move_ctor_calls; std::cout << "Object(Object&&):" << this << std::endl; }
3334
~Object() { std::cout << "~Object():" << this << std::endl; }
3435
};
3536

3637
int main() { // 关闭编译器优化
3738
{
3839
std::cout << "----> 临时对像 - 右值1" << std::endl;
3940
Object();
40-
std::cout << "----> 临时对像 - 右值2" << std::endl;
41-
Object obj = Object();
41+
std::cout << "----> 临时对像 - 右值2(具名对象 + std::move)" << std::endl;
42+
// 注意: 不能写 `Object obj = Object();` 来观察移动构造 ——
43+
// C++17 起 prvalue 直接初始化目标, 保证复制省略, 连
44+
// -fno-elide-constructors 也无法让那次移动发生。
45+
// 从具名对象 std::move 才是标准无关的观察方式。
46+
Object named;
47+
Object obj = std::move(named);
4248

4349
std::cout << "--------代码可修改区域-开始--------" << std::endl;
4450

@@ -51,6 +57,9 @@ int main() { // 关闭编译器优化
5157
objRef.data = 1; // 修改被延长生命周期的临时对象的值(不要直接改动这行代码)
5258
std::cout << "objRef.data = " << objRef.data << " - " << &objRef << std::endl;
5359
d2x_assert((&objRef == object_address));
60+
// 钉住移动构造确实发生过。教学漂移之所以能静默发生, 正是因为
61+
// 从前没有任何断言检查它 —— 输出少了一行, 没人发现。
62+
d2x_assert((move_ctor_calls >= 1));
5463
}
5564

5665
D2X_WAIT

dslings/en/cpp11/04-rvalue-references.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
struct Object;
2323
static Object * object_address = nullptr;
24+
static int move_ctor_calls = 0; // 移动构造被调用的次数, 供断言检查
2425

2526
struct Object {
2627
int data = 0;
@@ -29,16 +30,21 @@ struct Object {
2930
object_address = this;
3031
}
3132
Object(const Object&) { std::cout << "Object(const Object&):" << this << std::endl; }
32-
Object(Object&&) { std::cout << "Object(Object&&):" << this << std::endl; }
33+
Object(Object&&) { ++move_ctor_calls; std::cout << "Object(Object&&):" << this << std::endl; }
3334
~Object() { std::cout << "~Object():" << this << std::endl; }
3435
};
3536

3637
int main() { // Disable compiler optimization
3738
{
3839
std::cout << "----> Temporary object - rvalue 1" << std::endl;
3940
Object();
40-
std::cout << "----> Temporary object - rvalue 2" << std::endl;
41-
Object obj = Object();
41+
std::cout << "----> Temporary object - rvalue 2 (named object + std::move)" << std::endl;
42+
// NOTE: `Object obj = Object();` will NOT show a move constructor.
43+
// Since C++17 a prvalue initialises the target directly (guaranteed
44+
// copy elision), and -fno-elide-constructors cannot bring that move
45+
// back. Moving from a named object is the standard-independent way.
46+
Object named;
47+
Object obj = std::move(named);
4248

4349
std::cout << "--------Code modifiable area - Start--------" << std::endl;
4450

@@ -51,6 +57,9 @@ int main() { // Disable compiler optimization
5157
objRef.data = 1; // Modify the value of the extended lifetime temporary object (do not directly modify this line)
5258
std::cout << "objRef.data = " << objRef.data << " - " << &objRef << std::endl;
5359
d2x_assert((&objRef == object_address));
60+
// 钉住移动构造确实发生过。教学漂移之所以能静默发生, 正是因为
61+
// 从前没有任何断言检查它 —— 输出少了一行, 没人发现。
62+
d2x_assert((move_ctor_calls >= 1));
5463
}
5564

5665
D2X_WAIT

0 commit comments

Comments
 (0)