You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
3.8 KiB
133 lines
3.8 KiB
4 years ago
|
/*
|
||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||
|
*
|
||
|
* This source code is licensed under the MIT license found in the
|
||
|
* LICENSE file in the root directory of this source tree.
|
||
|
*/
|
||
|
|
||
|
#include <iostream>
|
||
|
|
||
|
namespace condtemp {
|
||
|
|
||
|
// keep track of how many copies are made of the object and how many
|
||
|
// of these copies have been destroyed
|
||
|
struct Counter {
|
||
|
std::string name;
|
||
|
int copies;
|
||
|
int copies_destroyed;
|
||
|
bool destroyed;
|
||
|
|
||
|
Counter(std::string name_)
|
||
|
: name(name_), copies(0), copies_destroyed(0), destroyed(false) {}
|
||
|
};
|
||
|
|
||
|
struct X {
|
||
|
int f; // some data
|
||
|
Counter* counter; // nullptr if this object is a copy from another X
|
||
|
Counter* original_counter; // nullptr if this object was created not from a
|
||
|
// copy or move constructor
|
||
|
|
||
|
X() = delete;
|
||
|
X(Counter* counter_) : counter(counter_), original_counter(nullptr), f(72) {
|
||
|
// std::cerr << "original: " << name() << "\n";
|
||
|
}
|
||
|
X(X& x) {
|
||
|
std::cerr << "copy (of " << x.name()
|
||
|
<< ") constructor called with f=" << x.f << "\n";
|
||
|
f = x.f + 11;
|
||
|
copy_from(x);
|
||
|
}
|
||
|
X(X&& x) {
|
||
|
std::cerr << "move (of " << x.name()
|
||
|
<< ") constructor called with f=" << x.f << "\n";
|
||
|
f = x.f + 10;
|
||
|
copy_from(x);
|
||
|
}
|
||
|
~X() {
|
||
|
std::cerr << "~X(" << f << ") " << name();
|
||
|
if (original_counter) {
|
||
|
original_counter->copies_destroyed++;
|
||
|
}
|
||
|
if (counter) {
|
||
|
std::cerr << " original destroyed";
|
||
|
counter->destroyed = true;
|
||
|
}
|
||
|
std::cerr << " \n";
|
||
|
;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
void copy_from(X& x) {
|
||
|
counter = nullptr;
|
||
|
if (x.counter) {
|
||
|
original_counter = x.counter;
|
||
|
} else {
|
||
|
original_counter = x.original_counter;
|
||
|
}
|
||
|
original_counter->copies++;
|
||
|
}
|
||
|
|
||
|
std::string& name() {
|
||
|
if (counter) {
|
||
|
return counter->name;
|
||
|
} else {
|
||
|
return original_counter->name;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
X copy(X x) {
|
||
|
std::cerr << "copy(" << x.f << ")\n";
|
||
|
return x;
|
||
|
}
|
||
|
|
||
|
void crash(bool b) {
|
||
|
if (b) {
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FP_track_copy_operations_one_copy_ok() {
|
||
|
Counter c_true("c_true"), c_false("c_false");
|
||
|
X y(&c_false);
|
||
|
X x = false ? X(&c_true) : y;
|
||
|
std::cerr << "c_false.copies=" << c_false.copies << "\n";
|
||
|
std::cerr << "c_false.copies_destroyed=" << c_false.copies_destroyed << "\n";
|
||
|
std::cerr << "c_false.destroyed=" << c_false.destroyed << "\n";
|
||
|
std::cerr << "c_true.copies=" << c_true.copies << "\n";
|
||
|
std::cerr << "c_true.copies_destroyed=" << c_true.copies_destroyed << "\n";
|
||
|
std::cerr << "c_true.destroyed=" << c_true.destroyed << "\n";
|
||
|
// these values were checked against the output of the program
|
||
|
// compiled with clang -fno-elide-constructors, results will vary
|
||
|
// if we omit the elidable constructor calls
|
||
|
if (!(c_false.copies == 2 && c_false.copies_destroyed == 1 &&
|
||
|
!c_false.destroyed) ||
|
||
|
c_true.copies != 0 || c_true.copies_destroyed != 0 || c_true.destroyed) {
|
||
|
int* p = nullptr;
|
||
|
*p = 42;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FP_track_copy_operations_complex_ok() {
|
||
|
Counter c_true("c_true"), c_false("c_false");
|
||
|
X y(&c_false);
|
||
|
X x = true ? copy(X(&c_true)) : y;
|
||
|
std::cerr << "c_false.copies=" << c_false.copies << "\n";
|
||
|
std::cerr << "c_false.copies_destroyed=" << c_false.copies_destroyed << "\n";
|
||
|
std::cerr << "c_false.destroyed=" << c_false.destroyed << "\n";
|
||
|
std::cerr << "c_true.copies=" << c_true.copies << "\n";
|
||
|
std::cerr << "c_true.copies_destroyed=" << c_true.copies_destroyed << "\n";
|
||
|
std::cerr << "c_true.destroyed=" << c_true.destroyed << "\n";
|
||
|
// these values were checked against the output of the program
|
||
|
// compiled with clang -fno-elide-constructors, results will vary
|
||
|
// if we omit the elidable constructor calls
|
||
|
if (!(c_true.copies == 4 && c_true.copies_destroyed == 3 &&
|
||
|
c_true.destroyed)) {
|
||
|
int* p = nullptr;
|
||
|
*p = 42;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // namespace condtemp
|
||
|
|
||
|
int main() { condtemp::FP_track_copy_operations_complex_ok(); }
|