引用具有已擦除类型 (void*) 的指针
Take a reference to a pointer with erased type (void*)
我可以从 T*
中取出 T*&
。现在我需要以类型擦除的方式存储我的 T*
,更具体地说是 void*
。我可以从 void*
中取出 T*&
吗? (当然,知道我的 void*
确实指向 T
s)
示例:
#include <iostream>
#include <cstdlib>
#include <numeric>
int main() {
int n = 10;
void* mdbuf = malloc(n*sizeof(double));
double* mdarr = (double*)mdbuf;
std::iota(mdarr,mdarr+n,0.); // initialize the memory with doubles
// solution 1: works but not what I want since I want to refer to the type-erased mdbuf variable
double*& mdarr_ref = mdarr; // ok, now mdarr_ref refers to variable mdarr
// solution 2: does not compile
double*& mdbuf_ref = (double*)mdbuf; // error: cannot bind non-const lvalue reference of type 'double*&' to an rvalue of type 'double*'
// solution 3: compiles and work but I want to be sure this is not out of pure luck: is it undefined behavior?
double*& mdbuf_ref = (double*&)mdbuf; // we would like mdbuf_ref to refer to variable mdbuf. It compiles...
std::iota(mdbuf_ref,mdbuf_ref+n,100.);
for (int i=0; i<n; ++i) {
std::cout << mdbuf_ref[i] << ", "; // ...does what we want in this case... is it valid however?
}
}
编辑:也许一种看待它的方式如下:
double d;
void* v_ptr = &d;
double* d_ptr = (double*)v_ptr; // (1) valid
double& d_ref = d; // (2) valid
double& d_ref2 = (double&)d; // (3) valid? Should be the same as (2) ?
double*& d_ref3 = (double*&)v_ptr; // (4)
问题是:(4) 有效吗?如果 (1) 和 (3) 成立,它只是将两者链接起来,所以我希望它是有效的,但我想要一些证据
你的方案1是唯一的答案;你。 (这个问题是关于 C 的,但是 C++ 引用的规则是等效的。)
我将以您的第二个示例为例,并使用别名重写其中的一部分,以更好地说明您的要求。
using V = void*;
using K = double*;
double d;
V v_ptr = reinterpret_cast<V>(&d);
V &v_ptr_ref1 = v_ptr; //Refers to the `V` object denoted by `v_ptr`.
K d_ptr = &d;
K &d_ptr_ref1 = d_ptr; //Refers to the `K` object denoted by `d_ptr`.
V &d_ptr_ref2 = reinterpret_cast<V&>(d_ptr);
因此,我们有两种类型:K
和 V
。在最后一行中,我们使用 K
类型的对象初始化对 V
的引用。所以d_ptr_ref2
被初始化为引用一个K
类型的对象,但是引用的类型是V
.
它们是否“只是”指针类型并不重要。在 C++ 中,指针是 对象类型 并且它们遵循任何其他对象类型的所有规则。
C++ 严格的别名规则禁止在某些非常特殊的情况之外通过不同类型的泛左值(如引用)访问一种类型的对象。具体的例外情况因版本而略有不同,但 没有 的 C++ 版本 void*
和 double*
是例外。
尝试访问 d_ptr_ref2
意味着您正在通过不相关类型 V
的引用访问类型 K
的对象。这违反了严格的别名,因此会产生未定义的行为。
我可以从 T*
中取出 T*&
。现在我需要以类型擦除的方式存储我的 T*
,更具体地说是 void*
。我可以从 void*
中取出 T*&
吗? (当然,知道我的 void*
确实指向 T
s)
示例:
#include <iostream>
#include <cstdlib>
#include <numeric>
int main() {
int n = 10;
void* mdbuf = malloc(n*sizeof(double));
double* mdarr = (double*)mdbuf;
std::iota(mdarr,mdarr+n,0.); // initialize the memory with doubles
// solution 1: works but not what I want since I want to refer to the type-erased mdbuf variable
double*& mdarr_ref = mdarr; // ok, now mdarr_ref refers to variable mdarr
// solution 2: does not compile
double*& mdbuf_ref = (double*)mdbuf; // error: cannot bind non-const lvalue reference of type 'double*&' to an rvalue of type 'double*'
// solution 3: compiles and work but I want to be sure this is not out of pure luck: is it undefined behavior?
double*& mdbuf_ref = (double*&)mdbuf; // we would like mdbuf_ref to refer to variable mdbuf. It compiles...
std::iota(mdbuf_ref,mdbuf_ref+n,100.);
for (int i=0; i<n; ++i) {
std::cout << mdbuf_ref[i] << ", "; // ...does what we want in this case... is it valid however?
}
}
编辑:也许一种看待它的方式如下:
double d;
void* v_ptr = &d;
double* d_ptr = (double*)v_ptr; // (1) valid
double& d_ref = d; // (2) valid
double& d_ref2 = (double&)d; // (3) valid? Should be the same as (2) ?
double*& d_ref3 = (double*&)v_ptr; // (4)
问题是:(4) 有效吗?如果 (1) 和 (3) 成立,它只是将两者链接起来,所以我希望它是有效的,但我想要一些证据
你的方案1是唯一的答案;你
我将以您的第二个示例为例,并使用别名重写其中的一部分,以更好地说明您的要求。
using V = void*;
using K = double*;
double d;
V v_ptr = reinterpret_cast<V>(&d);
V &v_ptr_ref1 = v_ptr; //Refers to the `V` object denoted by `v_ptr`.
K d_ptr = &d;
K &d_ptr_ref1 = d_ptr; //Refers to the `K` object denoted by `d_ptr`.
V &d_ptr_ref2 = reinterpret_cast<V&>(d_ptr);
因此,我们有两种类型:K
和 V
。在最后一行中,我们使用 K
类型的对象初始化对 V
的引用。所以d_ptr_ref2
被初始化为引用一个K
类型的对象,但是引用的类型是V
.
它们是否“只是”指针类型并不重要。在 C++ 中,指针是 对象类型 并且它们遵循任何其他对象类型的所有规则。
C++ 严格的别名规则禁止在某些非常特殊的情况之外通过不同类型的泛左值(如引用)访问一种类型的对象。具体的例外情况因版本而略有不同,但 没有 的 C++ 版本 void*
和 double*
是例外。
尝试访问 d_ptr_ref2
意味着您正在通过不相关类型 V
的引用访问类型 K
的对象。这违反了严格的别名,因此会产生未定义的行为。