不能将数组运算符用于基于数组的指针(读取访问冲突)

Posted

技术标签:

【中文标题】不能将数组运算符用于基于数组的指针(读取访问冲突)【英文标题】:can't use array operator to array-based pointers (read access violation) 【发布时间】:2019-07-18 16:05:44 【问题描述】:

基本上我想要实现的是使用指针,避免使用new 关键字来获得与其他一些语言相同的复制行为(如果我们交谈,运算符= 将右操作数的引用分配给左操作数关于对象,类似于 shared_ptr 应该提供的)。如果我不使用数组运算符[],我将展示的内容似乎有效。为什么会发生这种情况,我该如何解决?

// Declaration way before
std::vector<int>* test;

test = &std::vector<int>();
(*test)[1] = 0;
// Declaration way before
std::map<std::string, int>* test;

test = &std::map<std::string, int>();
(*test)["a"] = 0;

错误发生在两者的最后一行。

【问题讨论】:

test = &amp;std::vector&lt;int&gt;(); 创建一个向量,获取它的地址,然后向量立即停止存在。 不要试图让 C++ 表现得像其他语言一样。往往效果不佳。如果你想要一个引用,只需声明一个引用。 即使*test 指向一个实际的空向量,(*test)[1] 也会尝试访问一个不存在的元素。 相信我们,它确实不再存在。您正在做的事情称为未定义行为,一种可能的结果是它“有效”。 @uIM7AI9S 您的错误会导致未定义的行为。这意味着任何事情都可能发生。 C++ 中的许多(大多数?)错误不需要崩溃或诊断,这样的代码似乎可以工作一段时间。但事实是您的向量不存在,push_back 似乎只能工作。如果你依赖它,你最终将不可避免地开始在此处或代码的其他(看似无关的)部分中看到奇怪的崩溃和错误。不可能通过反复试验来学习 C++,没有明显的错误迹象并不能证明正确性。 【参考方案1】:
test = &std::vector<int>();

这不是有效的 C++。不能取临时地址。

不幸的是,作为扩展,Visual Studio 确实允许您这样做;你得到的指针是立即悬空(因为临时死在行尾)。然后,您尝试对向量(不存在)执行的所有操作都有未定义的行为。

(即使它是一个有效的指针,你也在尝试索引不存在的元素。)

只要您在范围内的某个位置保留一个适当的命名对象,您就可以做您想做的事。您可以获得指向该对象的指针并在所有地方获取您的引用语义。但是,这是危险的,因为很难确保指向的对象在需要时仍然存在。这就是存在智能指针的原因。

在 C++ 中,你最好坚持价值语义。最好按设计使用该语言。

【讨论】:

【参考方案2】:

您正在为指针分配对临时向量的引用。临时对象立即消失,您的指针悬空。

您还尝试访问具有0 大小的向量的第二个元素。

你可以试试这个,但我们已经不在 new delete 时代了。

std::vector<int>* test; 
test = new std::vector<int>(2); 
(*test)[1] = 0;

// done with test
delete test;

【讨论】:

【参考方案3】:

不能对基于数组的指针使用数组运算符

你可以,如果你的指针指向一个对象。你的没有。

使用指针,避免使用 new 关键字来获得与其他语言相同的复制行为

您还没有真正表现出您想要什么行为,或者说您要模仿哪种语言,但总的来说:用语言 B 编写语言 A 代码是一个坏主意。两者将有不同的约定、习语和微妙之处。

如果您确实坚持要编写看起来像另一种语言的 C++,您需要弄清楚您需要什么特定行为,以及如何在 C++ 中实现它以使其看起来相似。这通常需要大量工作,而编写看起来符合您想要的方式并且恰好可以编译的 C++ 代码并不是一个足够的解决方案。

正如 Lightness 指出了你的近似错误,我只想提一下,通过编写一个金丝雀类型来检查你对这些事情的理解是微不足道的,比如

struct Canary 
    ~Canary()  cout << "Canary dtor\n"; 
    Canary()  cout << "Canary default ctor\n"; 
    Canary(Canary &&)  cout << "Canary move ctor\n"; 
    Canary(const Canary &)  cout << "Canary copy ctor\n"; 
    Canary& operator=(Canary &&)  cout << "Canary move assignment\n"; return *this; 
    Canary& operator=(const Canary &)  cout << "Canary copy assignment\n"; return *this; 
;

Canary *c = &Canary();

现在您可以轻松地在调试器中单步调试您的代码,或者只是运行它并观察输出...

【讨论】:

以上是关于不能将数组运算符用于基于数组的指针(读取访问冲突)的主要内容,如果未能解决你的问题,请参考以下文章

[使用映射到1D的2D数组的访问冲突读取位置

为什么在尝试将指向数组的指针作为函数的参数时出现访问冲突错误?

如何通过 C++ 中指向该数组的指针访问另一个类中的数组?

《C程序设计语言》笔记 指针与数组

指向数组部分的指针。重载 [] 运算符以访问数组的各个部分

从共享内存中读取 int 数组是不是会排除银行冲突?