我在几个旧项目中看到过这样的代码:
class Class {
static void Method() {}
};
((Class*)0)->Method();
Run Code Online (Sandbox Code Playgroud)
此代码包含未定义的行为,因为它包括取消引用空指针(无论之后发生什么).这真的没有意义 - 演员是在那里将类型名称提供给编译器,并且编写上面代码的人可以写这个:
Class::Method();
Run Code Online (Sandbox Code Playgroud)
而后者也没关系.
为什么有人会写前代码?它是来自一些美好时光的已知成语还是什么?
最近尝试了以下程序,它编译,运行正常并产生预期的输出,而不是任何运行时错误.
#include <iostream>
class demo
{
public:
static void fun()
{
std::cout<<"fun() is called\n";
}
static int a;
};
int demo::a=9;
int main()
{
demo* d=nullptr;
d->fun();
std::cout<<d->a;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果未初始化的指针用于访问类和/或结构成员,则行为未定义,但为什么允许使用空指针访问静态成员.我的计划有什么危害吗?
建立
给定此用户定义的类型:
struct T
{
static int x;
int y;
T() : y(38);
};
Run Code Online (Sandbox Code Playgroud)
并在某处有用的必要定义:
int T::x = 42;
Run Code Online (Sandbox Code Playgroud)
以下是将标准int
值传递给stdout的规范方法:
std::cout << T::x;
Run Code Online (Sandbox Code Playgroud)
控制
同时,由于T
不存在的实例,以下(当然)无效:
T* ptr = NULL; // same if left uninitialised
std::cout << ptr->y;
Run Code Online (Sandbox Code Playgroud)
题
现在考虑以下代码的可怕和邪恶和坏:
T* ptr = NULL;
std::cout << ptr->x; // remember, x is static
Run Code Online (Sandbox Code Playgroud)
ptr
如上所述,取消引用无效.即使这里没有物理内存解除引用,我相信它仍然算作一个,使上面的代码UB.或者......是吗?
14882:2003 5.2.5/3明确表示a->b
转换为(*(a)).b
,并且:
评估点或箭头之前的后缀表达式; 即使结果不必确定整个后缀表达式的值,也会发生此评估,例如,如果id-expression表示静态成员.
但目前尚不清楚这里的"评估"是否涉及实际的解除引用.实际上,14882:2003和n3035似乎都没有明确地说明指针表达式在处理静态成员时是否必须求值为指向有效实例的指针.
我的问题是,这有多么无效?它是否真的被标准特别禁止(即使没有物理解除引用),或者它只是我们可以逃脱的语言的怪癖?即使它被禁止,我们还期望GCC/MSVC/Clang在多大程度上安全地对待它?
我的g ++ 4.4似乎生成的代码永远不会尝试将[invalid] this
指针推入堆栈,并关闭优化.
BTW如果T
是多态的,那么这不会影响这一点,因为静态成员不能是虚拟的.
在C++中对空对象进行fucntion调用时返回的布尔值是多少?
ClassDummy* dummy = NULL;
if (!dummy->dummy_function(1,2,3)) {
// Do Something
}
Run Code Online (Sandbox Code Playgroud)
根据C++ 11标准,这不应该返回错误吗?
说我有:
class A {
public:
static void DoStuff();
// ... more methods here ...
};
Run Code Online (Sandbox Code Playgroud)
后来我有一个想要调用DoStuff的函数:
B::SomeFunction(A* a_ptr) {
Run Code Online (Sandbox Code Playgroud)
是否更好地说:
a_ptr->DoStuff();
}
Run Code Online (Sandbox Code Playgroud)
或者更好,即使我有一个实例指针:
A::DoStuff()
}
Run Code Online (Sandbox Code Playgroud)
这纯粹是一种风格问题,但在做出决定之前,我想得到一些明智的意见.
此问题的后续问题
我们有以下代码:
#include <iostream>
struct A
{
static int n;
};
int A::n = 5;
int main()
{
A* a; //uninitialized on purpose
std::cout << a->n; //UB?
}
Run Code Online (Sandbox Code Playgroud)
这样的访问是否为未定义行为?一方面,不需要对象来访问静态类成员,另一方面,operator->
在未初始化的指针正在请求麻烦的情况下。
注意:GCC和MSVC会在没有任何警告的情况下编译此代码,Clang抱怨未初始化的用法。https://godbolt.org/z/Gy5fR2
这里出现了一个问题,当一个指针变得晃来晃去时,问"为什么这个工作".答案是它是UB,这意味着它可能起作用.
我在一个教程中学到了:
#include <iostream>
struct Foo
{
int member;
void function() { std::cout << "hello";}
};
int main()
{
Foo* fooObj = nullptr;
fooObj->member = 5; // This will cause a read access violation but...
fooObj->function(); // Because this doesn't refer to any memory specific to
// the Foo object, and doesn't touch any of its members
// It will work.
}
Run Code Online (Sandbox Code Playgroud)
这相当于:
static void function(Foo* fooObj) // Foo* essentially being the "this" pointer
{
std::cout << "Hello";
// Foo …
Run Code Online (Sandbox Code Playgroud)