由于未定义的行为,许多不好的事情发生并且继续发生(或者不知道,谁知道,任何事情都可能发生).据我所知,这是为了让编译器进行优化留下一些摆动空间,也可能使C++更容易移植到不同的平台和架构.然而,由未定义的行为引起的问题似乎太大而无法通过这些论证来证明.未定义行为的其他参数是什么?如果没有,为什么还存在未定义的行为?
编辑为我的问题添加一些动机:由于使用较少C++的几个糟糕经历 - 狡猾的同事,我已经习惯了使我的代码尽可能安全.断言每一个论点,严谨的正确性以及类似的东西.我试图离开,因为小房间可能以错误的方式使用我的代码,因为经验表明,如果有漏洞,人们会使用它们,然后他们会打电话给我,说我的代码很糟糕.我认为让我的代码尽可能安全是一种好的做法.这就是为什么我不明白为什么存在未定义的行为.有人可以给我一个未定义行为的例子,这些行为在运行时或编译时无法检测到而没有相当大的开销吗?
我刚刚阅读这篇文章,并希望得到大家的建议:
问:应该delete this;从成员方法中调用吗?
显然,取消引用无效指针会导致未定义的行为.但是如果只是在指针变量中存储无效的内存地址呢?
请考虑以下代码:
const char* str = "abcdef";
const char* begin = str;
if (begin - 1 < str) { /* ... do something ... */ }
Run Code Online (Sandbox Code Playgroud)
表达式begin - 1求值为无效的内存地址.请注意,我们实际上并没有取消引用此地址 - 我们只是在指针算法中使用它来测试它是否有效.尽管如此,我们仍然需要将无效的内存地址加载到寄存器中.
那么,这是不确定的行为吗?我从来没有想过,因为很多指针算法似乎依赖于这种事情,而指针实际上只是一个整数.但最近我听说即使将无效指针加载到寄存器中的行为也是未定义的行为,因为某些架构会自动抛出总线错误或者其他内容.任何人都可以向我指出C或C++标准的相关部分,无论哪种方式解决这个问题?
根据C++标准(3.7.3.2/4)使用(不仅是解除引用,还有复制,转换,其他任何),无效指针是未定义的行为(如果有疑问也会看到这个问题).现在,遍历STL容器的典型代码如下所示:
std::vector<int> toTraverse;
//populate the vector
for( std::vector<int>::iterator it = toTraverse.begin(); it != toTraverse.end(); ++it ) {
//process( *it );
}
Run Code Online (Sandbox Code Playgroud)
std::vector::end()是超出容器最后一个元素的假设元素的迭代器.那里没有元素,因此使用指针通过迭代器是未定义的行为.
那么!= end()工作怎么样呢?我的意思是为了进行比较,需要构造迭代器包装无效地址,然后必须在比较中使用该无效地址,这也是未定义的行为.这样的比较合法吗?为什么?
灵感来自这个问题.
假设在C++代码中我有一个有效的指针并且正确delete.根据C++标准,指针将变为无效(3.7.3.2/4 - 解除分配函数将使所有指针无效,指向解除分配的存储的所有部分).
至少在大多数实现中,它保留了值并将存储与以前完全相同的地址delete,但是使用该值是未定义的行为.
标准是否保证指针将保留其值或允许更改的值?
可能重复:
安全delete this吗?
我一直在为一个设计用作链表中的节点的类做一些工作,我想我会给类自己的删除功能而不是管理类这样做.所以基本上它是这样的:
void Class::Delete() {
//Some cleanup code before deleting the object
delete this;
}
Run Code Online (Sandbox Code Playgroud)
现在我已经对它进行了测试,看起来效果很好,但是我过去遇到过一个问题,即对象一直在运行代码,被删除,然后显然是通过尝试使用不再使程序崩溃存在的对象.
由于"删除这个"就在函数的末尾,它显然退出了函数并且工作正常,但这种做法是不是一个坏主意?如果我不小心,这会不会在我的脸上爆炸?
事实证明,许多无辜的东西都是C++中未定义的行为.例如,一旦一个非空的指针已被delete"D 甚至在打印的是指针的值是未定义的行为.
现在内存泄漏肯定是坏事.但他们是什么类的情况 - 定义,未定义或其他类别的行为?
我刚刚在programmers.stackexchange上遇到过这个问题,并且看到了关于在delete this;成员函数内部进行操作的问题.
根据我的理解,这通常是禁止的,但是在某些情况下这可能是有用的.什么时候会有用,哪些技术原因没有?
我在我的C++程序中使用外部C库,并且库使用必须返回的回调函数void*.库检查返回值是否为NULL,这意味着成功.
那么告诉它一切都很好的最佳方法是什么?
我用:
return reinterpret_cast<void*>(1);
Run Code Online (Sandbox Code Playgroud)
但它看起来很难看......
编辑:谢谢你的回复,我会留下这个:
static int success;
return &success;
Run Code Online (Sandbox Code Playgroud) 从示例中我看到COM IUnknown::Release()函数实现是这样的:
ULONG Release()
{
InterlockedDecrement(&m_count);
if(m_count == 0) {
delete this;
}
return m_count;
}
Run Code Online (Sandbox Code Playgroud)
因此,如果m_count为0,那么我们将删除"this"对象,并返回引用计数.我不明白为什么它有效?!?!
删除对象不会破坏调用堆栈,也可以,因为它是由线程保存的,所以它与对象无关???
如果对象已被删除,我们怎么可能返回m_count,它应该被删除.我可以说服自己,如果在删除代码后会返回硬编码0,这是可以的,但是为什么它会返回会员?!?!
非常感谢你的帮助!:-)