reinterpret_cast 何时违法?

问题描述 投票:0回答:1

我写了一段代码,积累了不必要的内存空间,并在需要时将其归还,将其组织为堆栈(客户的要求很奇怪)

void* stack = nullptr;

template <typename P>
void push(P* p) {
  // reinterpret memory space of *p as a storage for the address of the top element of the stack;
  *reinterpret_cast<void**>(p) = stack;
  // now *p is the top element, so update stack to point to *p;
  stack = p;
}

template <typename P>
P* pop() {
  if (stack == nullptr) throw;

  // get the address of the top element
  P* p = static_cast<P*>(stack);
  // now stack should point to the next element after *p, which address is stored in *p's memory space
  stack = *reinterpret_cast<void**>(stack);
  return p;
}

stack
是指向顶部元素的指针。当新的内存空间为
pushed
时,其前 8 个字节用于存储前一个元素的地址,
stack
被更新。一个简单的栈链。

问题

当我试图实现这种行为时,编译器经常这样说(我知道某些内存操作是非法的):

对强制转换的赋值是非法的,不支持左值强制转换

我想知道我的实施现在是否合法

示例

#include <iostream>
#include <bitset>

constexpr size_t bytes_8  = 8 * 8;
constexpr size_t bytes_20 = 8 * 20;
constexpr size_t bytes_50 = 8 * 50;

// we assume that std::bitset holds its data contigiously in the beginning

struct A {
  std::bitset<bytes_8> bits;
};

struct B {
  std::bitset<bytes_20> bits;
};

struct C {
  std::bitset<bytes_50> bits;
};
int main() {
  // Imagine they were allocated on heap:
  A a;  B b;  C c;

  std::cout << "Addresses" << '\n'
            << "a: " << &a << "\t"
            << "b: " << &b << "\t"
            << "c: " << &c
            << std::endl << std::endl << std::endl;

  push<A>(&a);
  std::cout << "---------- push<A>(&a) ----------\n"
            << "'a' is the top element (and the only one), so 'stack' points to it,\n"
            << "meanwhile 'a' stores the address of the previous element (none)\n\n"
            << "stack: " << stack << "\ta.bits: " << std::hex << a.bits.to_ullong()
            << std::endl << std::endl;

  push<B>(&b);
  std::cout << "---------- push<B>(&b) ----------\n"
            << "now 'b' is the top element, so 'stack' updates to point to it,\n"
            << "'b' stores the address of the previous element (a)\n\n"
            << "stack: " << stack << "\tb.bits: " << std::hex << b.bits.to_ullong()
            << std::endl << std::endl;

  push<C>(&c);
  std::cout << "---------- push<C>(&c) ----------\n"
            << "finally 'c' is the top element and 'stack' points to it,\n"
            << "'c' stores the address of the previous element (b)\n\n"
            << "stack: " << stack << "\tc.bits: " << std::hex << c.bits.to_ullong()
            << std::endl << std::endl << std::endl;


  auto p1 = pop<C>();
  std::cout << "---------- pop<C>() ----------\n"
            << "'b' is the top element and the next one after it is 'a'\n\n"
            << "ret: " << p1 << "\nstack: " << stack << "\tb.bits: " << std::hex << b.bits.to_ullong()
            << std::endl << std::endl;

  auto p2 = pop<B>();
  std::cout << "---------- pop<B>() ----------\n"
            << "'a' is the top element and the last one in the stack\n\n"
            << "ret: " << p2 << "\nstack: " << stack << "\ta.bits: " << std::hex << a.bits.to_ullong()
            << std::endl << std::endl;

  auto p3 = pop<A>();
  std::cout << "---------- pop<A>() ----------\n"
            << "the stack is empty\n\n"
            << "ret: " << p3 << "\nstack: " << "0x" << stack
            << std::endl << std::endl;

  return 0;
}
输出:
Addresses
a: 0x7fffffffdc20       b: 0x7fffffffdc40       c: 0x7fffffffdc60


---------- push<A>(&a) ----------
'a' is the top element (and the only one), so 'stack' points to it,
meanwhile 'a' stores the address of the previous element (none)

stack: 0x7fffffffdc20   a.bits: 0

---------- push<B>(&b) ----------
now 'b' is the top element, so 'stack' updates to point to it,
'b' stores the address of the previous element (a)

stack: 0x7fffffffdc40   b.bits: 7fffffffdc20

---------- push<C>(&c) ----------
finally 'c' is the top element and 'stack' points to it,
'c' stores the address of the previous element (b)

stack: 0x7fffffffdc60   c.bits: 7fffffffdc40


---------- pop<C>() ----------
'b' is the top element and the next one after it is 'a'

ret: 0x7fffffffdc60
stack: 0x7fffffffdc40   b.bits: 7fffffffdc20

---------- pop<B>() ----------
'a' is the top element and the last one in the stack

ret: 0x7fffffffdc40
stack: 0x7fffffffdc20   a.bits: 0

---------- pop<A>() ----------
the stack is empty

ret: 0x7fffffffdc20
stack: 0x0
c++ reinterpret-cast illegal-instruction
1个回答
0
投票

即使您设法删除未定义的行为,您的实现也不可能工作。

将元素推入堆栈会覆盖其中的一部分。这是一个有损操作。

sizeof void*
对象表示开头的
*p
字节已经消失,永远无法恢复。即使您不再使用该对象,它的析构函数仍然需要运行,并且通常需要该数据。

© www.soinside.com 2019 - 2024. All rights reserved.