here is the code:
expected behavior: In ~X() the ptr shoule be != nil no matter the IS_ERR macro is defined or not
#include <iostream>
#include <functional>
#include <vector>
#include <memory>
struct X {
X(std::function<void()> f): f_{std::move(f)} {}
~X() {
f_();
}
std::function<void()> f_;
};
std::shared_ptr<int> func() {
std::shared_ptr<int> ptr;
X x([&] {
std::cout << "dtor, ptr == null? " << (ptr == nullptr) << ", addr " << (long long)(&ptr) << std::endl;
});
if (ptr = std::make_shared<int>(100)) {
std::cout << "return, ptr == null? " << (ptr == nullptr) << ", addr " << (long long)(&ptr) << std::endl;
return ptr;
}
#if defined(IS_ERR)
return nullptr;
// return, ptr == null? 0, addr 140732821766368
// dtor, ptr == null? 1, addr 140732821766368 // ATTENTION: ptr == nil here !!!! the internal of ptr is moved to the caller before the destructor of X is executed even if there is no receiver in the caller.
// fini, ptr == null? 0, addr 140732821766576
#else
// return, ptr == null? 0, addr 140732879315376
// dtor, ptr == null? 0, addr 140732879315376 // ATTENTION ptr != nil the expected behavior
// fini, ptr == null? 0, addr 140732879315376
return ptr;
#endif
}
int main()
{
auto ptr = func();
std::cout << "fini, ptr == null? " << (ptr == nullptr) << ", addr " << (long long)(&ptr) << std::endl;
}
- in the defined(IS_ERR)
// ATTENTION: ptr == nil here !!!! the internal of ptr is moved to the caller before the destructor of X is executed even if there is no receiver in the caller.
- in the no defined(IS_ERR)
// ATTENTION ptr != nil the expected behavior
- the code is tested under followings enviornments:
g++ --version : g++ (GCC) 4.8.2 20140120 (Red Hat 4.8.2-15)
Apple LLVM version 10.0.1 (clang-1001.0.46.4) Target: x86_64-apple-darwin18.7.0
the test result is the same:
rm -f test && clang++ -o test test.cc -std=c++11 -Wno-parentheses && ./test | grep dtor
dtor, ptr == null? 0, addr 140732827398560
rm -f test && clang++ -o test test.cc -std=c++11 -DIS_ERR -Wno-parentheses && ./test | grep dtor
dtor, ptr == null? 1, addr 140732832612560
rm -f test && clang++ -o test test.cc -std=c++11 -O3 -Wno-parentheses && ./test | grep dtor
dtor, ptr == null? 0, addr 140732887884168
rm -f test && clang++ -o test test.cc -std=c++11 -O3 -DIS_ERR -Wno-parentheses && ./test | grep dtor
dtor, ptr == null? 1, addr 140732702822624
rm -f test && g++ -o test test.cc -std=c++11 -Wno-parentheses && ./test | grep dtor
dtor, ptr == null? 0, addr 140735881081728
rm -f test && g++ -o test test.cc -std=c++11 -DIS_ERR -Wno-parentheses && ./test | grep dtor
dtor, ptr == null? 1, addr 140722084209920
rm -f test && g++ -o test test.cc -std=c++11 -O3 -Wno-parentheses && ./test | grep dtor
dtor, ptr == null? 0, addr 140736717254624
rm -f test && g++ -o test test.cc -std=c++11 -O3 -DIS_ERR -Wno-parentheses && ./test | grep dtor
dtor, ptr == null? 1, addr 140735485800352
- the use case of the example code is as follows:
using Error = std::shared_ptr<std::string>;
// go style error propagation is simulated here
Error func() {
Error err;
X x([&] {
if (err) {
// ATTENTION: we may do something here, like logging, alerting
} else {
// or we any do something REALLY REALLY IMPORTANT here, like express, transferring money ... it may cause catastrophic result ... (it is actually err != nil, but you think the result is ok ...)
}
});
err = doSomeThing()
if (err) {
err = Wrap(err, "do func");
return err;
}
#if defined(IS_ERR)
return nullptr;
#else
return err;
#endif
}
Aucun commentaire:
Enregistrer un commentaire