【发布时间】:2019-05-20 17:42:00
【问题描述】:
当条件运算符c?x:y 的两个返回参数的类型不同时,会在应用强制转换之前进行复制。可以在保持简单易用性的同时防止这种情况吗?
我有这个(因问题而删减):
struct Fixed {
char data[10];
Fixed(char *s) { strcpy(data, s); }
operator char*() { return this->data; }
};
但它对条件运算符和 nullptr 的行为非常糟糕:
Fixed f =...; // just here to show the type of f, don't read too much into this
...
bool condition = ...;
char *s = condition ? nullptr : f;
制作了 f 的副本,并且 s 现在指向堆栈上的一个值,该值将很快消失。这一切都是因为nullptr 的类型是std::nullptr_t。 f 将通过演员表传递给char*,但只有在它首先被复制之后。这似乎是非常糟糕的行为,但这是规范所说的。
我目前的解决方法是只制作演员和演员explicit,但这有点破坏可用性。还有其他解决方案吗?
这里有一些示例代码可供使用(忽略质量,因为我正在大量使用它以了解 gcc 和 LLVM 如何以不同方式处理此问题):
#include <cstdio>
#include <iostream>
#include <array>
#include <cstring>
using namespace std;
struct A : public array<char,4> {
A() { cerr<<"def\n"; }
A(const A &o) { cerr<<"copy\n"; (*this)=o;}
A(const char *s) { cerr<<"ctor\n";assign(s); } // explicit fixes
void assign(const char*s) {cerr<<"assign\n";memset(this->begin(), 0, 4); strncpy(this->begin(), s, 4); }
operator char*() { cerr<<"cast\n";return this->begin(); }
//operator void*() { cerr<<"void\n";return this->begin(); }
//operator std::nullptr_t() { cerr<<"void\n";return (std::nullptr_t)this->begin(); }
};
volatile A *faraway = new A();
char* plain(A &v) { cerr<<"in pl\n";
return faraway == nullptr ? nullptr : v;
}
char* cast1(A &v) { cerr<<"in c1\n";
return faraway == nullptr ? (char*)nullptr : v;
}
char* cast2(A &v) { cerr<<"in c2\n";
return faraway == nullptr ? nullptr : (char*)v;
}
int main() {
A *a = new A; a->assign("asd");
char *x = a->data();
cerr << "\nplain\n";
char *yp = plain(*a);
cerr << "\nc1\n";
char *y1 = cast1(*a);
cerr << "\nc2\n";
char *y2 = cast2(*a);
cerr << "\n---\n";
cerr << (void*)a << "\n" << (void*)(a->data()) << "\n" << (void*)x << "\n---\n";
cerr << (void*)yp << "\n" << (void*)y1 << "\n" << (void*)y2 << "\n";
return 0;
}
【问题讨论】:
-
这里发生了很多奇怪的事情
cond?nullptr:(char*)f工作正常。cond?(char*)nullptr:f在 LLVM 中工作正常,但 GCC 拒绝编译(我明确指定了Fixed(char*)ctor)。 -
@JohnKugelman 是的,基本上。我只是在那里展示
f的类型。该结构是从哈希中检索的,因此我尝试在哈希中返回结构的char*,而不是返回堆栈上结构副本的char*。 -
使用
somefunc(A &v)然后&v不能为nullptr。请展示一个更好的例子或更好的设计。 -
@Ripi2:令人惊讶的是,这不是真的。你可以做
somefunc(*(A*)nullptr),只要不做左值到右值的转换是合法的。 -
@BenVoigt 给我一个惊喜,是的。无论如何,我认为 OP 想要使用
char *x = somefunc(someinstance),其中someinstance不是指针,而是类实例。
标签: c++ conditional-operator temporary-objects