简体   繁体   English

static_cast 对 void* 的 const 引用

[英]static_cast const reference to void*

I have a const reference to a void*:我有一个对 void* 的 const 引用:

void* p;
void* const& x = p;

I'd like to cast it to a const reference to a T* (for some struct T {}; ).我想将它转换为对 T* 的 const 引用(对于某些struct T {}; )。 Of the three ways I can think of doing this, my default choice of static_cast doesn't work:在我能想到的三种方法中,我默认的static_cast选择不起作用:

T* const& y = static_cast<T* const&>(x);       // doesn't work
T* const& y = reinterpret_cast<T* const&>(x);  // works
T* const& y = (T* const&) x;                   // works

GCC gives the following error: GCC 给出以下错误:

error: invalid static_cast from type ‘void* const’ to type ‘T* const&’
       T* const& y = static_cast<T* const&>(x);

I'd like to understand what it means, and if there is a way to fix it.我想了解它的含义,以及是否有办法解决它。


EDIT (2019-11-26):编辑(2019-11-26):

There is a discussion in the comments and answers about whether T* const& (and void* const& ) is评论和答案中有关于T* const& (和void* const& )是否为

  1. a const reference to T* ;T*的 const 引用; or或者
  2. a reference to const T* .const T*的引用。

The consensus in the comments seems to be that it's option 2. But from the following example, it seems to me that it's option 1.评论中的共识似乎是选项 2。但是从以下示例中,在我看来它是选项 1。

Suppose I have a class T with a non-const function f() :假设我有一个带有非常量函数f() T类:

struct T
{
  void f() {};  // NB: non-const
};

We can consider two options:我们可以考虑两种选择:

const T*  x;
T* const& y;

Calling f() via them produces different effects:通过它们调用f()会产生不同的效果:

x->f();   // compile-time error (passing ‘const T’ as ‘this’ argument discards qualifiers)
y->f();   // works fine

Does this not suggest that option 1 is correct?这不表明选项 1 是正确的吗? Can somebody reconcile this for me?有人可以为我调和吗?

You can't bind a reference to any other type (except a less cv-qualified version of the same type or certain subtle things involving reading individual bytes via special types like unsigned char& ).您不能将引用绑定到任何其他类型(除了相同类型的较少 cv 限定版本或某些涉及通过特殊类型(如unsigned char& )读取单个字节的微妙事物)。 If you force the matter with a reinterpret_cast (including via a C-style cast), it's undefined behavior to use the result (other than by casting it back).如果您使用reinterpret_cast (包括通过 C 风格的强制转换)强制执行该问题,则使用结果(而不是通过将其返回)是未定义的行为。

You can (with merely static_cast ) convert a void* value to T* , and you can make conveniences like您可以(仅使用static_cast )将void*转换为T* ,并且您可以提供诸如

const auto y=[&] {return static_cast<T*>(p);};

so that you can track p 's current value by writing y() anywhere later.这样您就可以通过稍后在任何地方编写y()来跟踪p的当前值。 (Since it returns by value, you indeed can't write y()=new T , as desired.) (由于它按值返回,因此您确实无法根据需要编写y()=new T 。)

That is how the language casts work. 这就是语言转换的工作方式。 Here is a simple, lacking overview: 这是一个简单的,缺少概述的内容:

  • const_cast Converts between types with different cv-qualification. const_cast在具有不同cv资格的类型之间转换。
  • static_cast is intended for safe casts. static_cast用于安全转换。 Integer conversions, conversion operators or conversion constructors are some example that static_cast can do. 整数转换,转换运算符或转换构造函数是static_cast可以执行的一些示例。
  • dynamic_cast is intended for polymorphism dynamic_cast适用于多态
  • reinterpret_cast is a last resort option, allows basically any conversion by reinterpreting the underlying bit patterns. reinterpret_cast是不得已的选择,通过重新解释基础位模式,基本上可以进行任何转换。
  • explicit C-style cast is considered a leftover from C. It will use the "best" cast in the context. 显式C样式转换被认为是C的遗留物。它将在上下文中使用“最佳”转换。 In your example it is equivalent with reinterpret_cast . 在您的示例中,它等效于reinterpret_cast

Conversion from a void* to T* (both save cv) is valid iff the original pointer was of type T* aka at the pointed location there exists an object of type T . void*T*转换(都保存cv)是有效的,前提是原始指针的类型为T*又在指向的位置处存在类型为T的对象。 As you can see the conversion is "dangerous" in the sense that if the condition is not true you have UB (an invalid program). 如您所见,如果条件不成立,则转换是“危险的”,即您拥有UB(无效程序)。 So you can only do that with reinterpret_cast . 因此,您只能使用reinterpret_cast做到这一点。

Looking at your original problem of not wanting to modify a value via a certain pointer the following should work.查看不想通过某个指针修改值的原始问题,以下应该有效。 Templating it should give the same result.模板化它应该给出相同的结果。 Bring in references if you need to but it will have the same result.如果需要,请引入参考文献,但结果相同。

void myfunc1(int* intptr)
{
    (*intptr)++;
    std::cout << "In myfunc1 "<< *intptr<<"\n";
}

void myfunc2(const int* intptr)
{
    //(*intptr)++; //modification not possible
    std::cout << "In myfunc2 " << *intptr << "\n";
}

int main()
{       
    int* val = new int;
    *val = 32;

    void*  p = val; 

    std::cout << "Before myfunc1 " << *val << "\n";
    myfunc1(static_cast<int*>(p));
    std::cout << "After myfunc1 "<<*val<<"\n";

    //no modification via pointer to const
    const int* x = static_cast<const int*>(p);
    myfunc2(x);
    std::cout << "After myfunc2 " << *val << "\n";

There's no const reference. 没有const参考。 In C++ references are not assignable (you can only initialize them). 在C ++中, 引用是不可分配的(只能对其进行初始化)。 Also void* const& doesn't mean a const reference to void * . 同样, void* const&并不意味着对void *的const引用。 It instead means a reference to a const pointer to void. 相反,它意味着对指向void的const指针的引用。 In the statement below you're just initializing a reference, so you don't need to mention reference in static_cast . 在下面的语句中,您只是初始化一个引用,因此您无需在static_cast提及引用。

T* const& y = static_cast<T* const&>(x);

The correct form is: 正确的形式是:

T* const& y = static_cast<T* const>(x);

Update #1 更新#1

There is a discussion in the comments and answers about whether T* const& (and void* const&) is 评论和答案中有一个讨论,关于T * const&(和void * const&)是否为

Neither 1 nor 2. Please note that const T* is different than T* const . 1和2都不是。请注意const T*T* const不同。 Former is a non-const pointer to const T, whereas the latter is a const pointer to a non-const T. Thus, T* const& means a reference to a const pointer to a non-const T. 前者是指向const T的非const指针,而后者是指向非const T的const指针。因此, T* const&表示对指向非const T的const指针的引用。

Also regarding the following example, 同样关于以下示例,

struct T
{
  void f() {};  // NB: non-const
};

given const T* x; 给定const T* x; , you cannot call x->f(); ,则无法调用x->f(); . because x is a pointer to const T but function f needs a non-const T, so you cannot initialize a non-const variable with a const variable as this discards const qualifier. 因为x是指向const T的指针,但是函数f需要一个非const T,所以您不能使用const变量来初始化非const变量,因为这会丢弃const限定符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM