【发布时间】:2015-01-23 23:24:48
【问题描述】:
我正在尝试编写一个调试宏/模板,它输出函数的名称,后跟返回值,然后返回该值。我想出了 4 个 makros:RETURN 用于基本类型,RETURN_P 用于 std 包装器中的指针(uniqe_ptr,shared_ptr,可选),RETURN_B 用于布尔值,RETURN_A 用于我只能显示地址的东西.
为了测试宏,我编写了一个Resource 类,该类可移动但不可复制,并具有“私有”构造函数。我使用私有访问参数来防止任何人调用构造函数,同时保留使用 std::make_unique 等转发函数的能力。这是一个测试对象,因此它为我迄今为止遇到的所有类型提供了工厂。对于每种类型,都有一个工厂创建类型作为 makro 调用的一部分,以及一个工厂首先创建一个临时变量,然后使用它调用 makro。
最后,main() 函数创建了许多 Resource 对象来测试所有宏指令,包括 int 和 bool 基本类型。
现在这是我的问题:
- 使用定义了 NDEBUG 的
alloc_opt2和create2方法调用资源的移动构造函数。可以通过某种方式避免这种情况吗? - 当未定义 NDEBUG 时,
alloc_opt和create方法也会调用 Resource 的移动构造函数。我真的想至少消除这些动作,这样无论有没有 NDEBUG 的行为都是一样的。
有什么可以做的吗?
#include <memory>
#include <tuple>
#include <experimental/optional>
#include <cassert>
#include <stdio.h>
class Resource {
struct access { };
public:
static Resource * alloc_ptr();
static Resource * alloc_ptr2();
static std::unique_ptr<Resource> alloc_uniqe();
static std::unique_ptr<Resource> alloc_uniqe2();
static std::shared_ptr<Resource> alloc_shared();
static std::shared_ptr<Resource> alloc_shared2();
static std::experimental::optional<Resource> alloc_opt();
static std::experimental::optional<Resource> alloc_opt2();
static Resource create();
static Resource create2();
Resource(access);
~Resource();
Resource(Resource &&other);
operator bool() const;
private:
Resource(const Resource &) = delete;
Resource & operator =(const Resource &) = delete;
bool valid;
};
#define NDEBUG
#ifdef NDEBUG
#define RETURN(format, arg) return arg;
#define RETURN_P(arg) return arg;
#define RETURN_B(arg) return arg;
#define RETURN_A(arg) return arg;
#else
template <class T>
T debug(const char *format, const char *name, T && t) {
fprintf(stderr, "[<T>] ");
fprintf(stderr, format, name, t);
return std::forward<T>(t);
}
template <class T>
T debug_p(const char *format, const char *name, T && t) {
fprintf(stderr, "[ptr<T>] ");
fprintf(stderr, format, name, t ? &*t : nullptr);
return std::forward<T>(t);
}
bool debug_b(const char *format, const char *name, bool t) {
fprintf(stderr, "[bool] ");
fprintf(stderr, format, name, t ? "true" : "false");
return t;
}
template <class T>
T debug_a(const char *format, const char *name, T && t) {
fprintf(stderr, "[&<T>] ");
fprintf(stderr, format, name, &t);
return std::forward<T>(t);
}
#define RETURN(format, arg) return debug("%s : " format "\n", __PRETTY_FUNCTION__, arg);
#define RETURN_P(arg) return debug_p("%s = %p\n", __PRETTY_FUNCTION__, arg);
#define RETURN_B(arg) return debug_b("%s = %s\n", __PRETTY_FUNCTION__, arg);
#define RETURN_A(arg) return debug_a("%s = %p\n", __PRETTY_FUNCTION__, arg);
#endif
Resource * Resource::alloc_ptr() {
fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
RETURN_P(new Resource(access{}));
}
Resource * Resource::alloc_ptr2() {
fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
Resource * r = new Resource(access{});
RETURN_P(r);
}
std::unique_ptr<Resource> Resource::alloc_uniqe() {
fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
RETURN_P(std::make_unique<Resource>(access{}));
}
std::unique_ptr<Resource> Resource::alloc_uniqe2() {
fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
std::unique_ptr<Resource> r = std::make_unique<Resource>(access{});
RETURN_P(std::move(r));
}
std::shared_ptr<Resource> Resource::alloc_shared() {
fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
RETURN_P(std::make_shared<Resource>(access{}));
}
std::shared_ptr<Resource> Resource::alloc_shared2() {
fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
std::shared_ptr<Resource> r = std::make_shared<Resource>(access{});
RETURN_P(r);
}
std::experimental::optional<Resource> Resource::alloc_opt() {
fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
RETURN_P(std::experimental::optional<Resource>(std::experimental::in_place, access{}));
}
std::experimental::optional<Resource> Resource::alloc_opt2() {
fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
std::experimental::optional<Resource> r = std::experimental::optional<Resource>(std::experimental::in_place, access{});
RETURN_P(std::move(r));
}
Resource Resource::create() {
fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
RETURN_A(Resource(access{}));
}
Resource Resource::create2() {
fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
Resource r = Resource(access{});
RETURN_A(std::move(r));
}
Resource::Resource(access) : valid(true) {
fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
}
Resource::~Resource() {
fprintf(stderr, "%s [%s]\n", __PRETTY_FUNCTION__,
valid ? "valid" : "invalid");
valid = false;
}
Resource::Resource(Resource &&other) : valid(other.valid) {
fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
assert(other.valid);
other.valid = false;
}
Resource::operator bool() const {
fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
RETURN_B(valid);
}
int test_int() {
fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
RETURN("%d", 1);
}
int main() {
fprintf(stderr, "### test test_int()\n");
{
int i = test_int();
fprintf(stderr, "### test test_int() created\n");
if (i) { }
}
fprintf(stderr, "### test test_int() done\n\n");
fprintf(stderr, "### test Resource::alloc_ptr()\n");
{
Resource * r1 = Resource::alloc_ptr();
fprintf(stderr, "### test Resource::alloc_ptr() allocated\n");
delete r1;
}
fprintf(stderr, "### test Resource::alloc_ptr() done\n\n");
fprintf(stderr, "### test Resource::alloc_ptr2()\n");
{
Resource * r1 = Resource::alloc_ptr2();
fprintf(stderr, "### test Resource::alloc_ptr2() allocated\n");
delete r1;
}
fprintf(stderr, "### test Resource::alloc_ptr2() done\n\n");
fprintf(stderr, "### test Resource::alloc_unique()\n");
{
std::unique_ptr<Resource> r2 = Resource::alloc_uniqe();
fprintf(stderr, "### test Resource::alloc_uniqe() allocated\n");
if (r2) { }
}
fprintf(stderr, "### test Resource::alloc_uniqe() done\n\n");
fprintf(stderr, "### test Resource::alloc_unique2()\n");
{
std::unique_ptr<Resource> r2 = Resource::alloc_uniqe2();
fprintf(stderr, "### test Resource::alloc_uniqe2() allocated\n");
if (r2) { }
}
fprintf(stderr, "### test Resource::alloc_uniqe2() done\n\n");
fprintf(stderr, "### test Resource::alloc_shared()\n");
{
std::shared_ptr<Resource> r3 = Resource::alloc_shared();
fprintf(stderr, "### test Resource::alloc_shared() allocated\n");
if (r3) { }
}
fprintf(stderr, "### test Resource::alloc_shared() done\n\n");
fprintf(stderr, "### test Resource::alloc_shared2()\n");
{
std::shared_ptr<Resource> r3 = Resource::alloc_shared2();
fprintf(stderr, "### test Resource::alloc_shared2() allocated\n");
if (r3) { }
}
fprintf(stderr, "### test Resource::alloc_shared2() done\n\n");
fprintf(stderr, "### test Resource::alloc_opt()\n");
{
std::experimental::optional<Resource> r4 = Resource::alloc_opt();
fprintf(stderr, "### test Resource::alloc_opt() allocated\n");
if (r4) { }
}
fprintf(stderr, "### test Resource::alloc_opt() done\n\n");
fprintf(stderr, "### test Resource::alloc_opt2()\n");
{
std::experimental::optional<Resource> r4 = Resource::alloc_opt2();
fprintf(stderr, "### test Resource::alloc_opt2() allocated\n");
if (r4) { }
}
fprintf(stderr, "### test Resource::alloc_opt2() done\n\n");
fprintf(stderr, "### test Resource::create()\n");
{
Resource r5(Resource::create());
fprintf(stderr, "### test Resource::create() created\n");
if (r5) { }
}
fprintf(stderr, "### test Resource::create() done\n\n");
fprintf(stderr, "### test Resource::create2()\n");
{
Resource r5(Resource::create2());
fprintf(stderr, "### test Resource::create2() created\n");
if (r5) { }
}
fprintf(stderr, "### test Resource::create2() done\n\n");
}
【问题讨论】:
标签: c++ c++11 constructor move