请考虑以下代码:
#include <iostream>
struct foo
{
// (a):
void bar() { std::cout << "gman was here" << std::endl; }
// (b):
void baz() { x = 5; }
int x;
};
int main()
{
foo* f = 0;
f->bar(); // (a)
f->baz(); // (b)
}
Run Code Online (Sandbox Code Playgroud)
我们期望(b)崩溃,因为x空指针没有相应的成员.在实践中,(a)不会崩溃,因为this从不使用指针.
因为(b)取消引用this指针((*this).x = 5;),并且this为null,程序进入未定义的行为,因为取消引用null总是被称为未定义的行为.
会(a)导致未定义的行为吗?如果两个函数(和x)都是静态的呢?
c++ standards-compliance null-pointer undefined-behavior language-lawyer
我有以下代码片段:
class ABC{
public:
int a;
void print(){cout<<"hello"<<endl;}
};
int main(){
ABC *ptr = NULL:
ptr->print();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它运行成功.有人可以解释一下吗?
#include "iostream"
using namespace std;
class A
{
public:
void mprint()
{
cout<<"\n TESTING NULL POINTER";
}
};
int main()
{
A *a = NULL;
a->mprint();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我输出为"TESTING NULL POINTER".任何人都可以解释为什么这个程序打印输出而不是崩溃.我在Dev C++和aCC编译器上检查了它们都给出了相同的结果.
让我们说我们上课了
class A
{
int x;
public:
void sayHi()
{
cout<<"Hi";
}
};
int main()
{
A *a=NULL;
a->sayHi();
}
Run Code Online (Sandbox Code Playgroud)
上面的代码将在Turbo C(我测试过的地方)上编译并Hi作为输出打印.
我原以为a是因为崩溃了NULL.sayHi()它说,如果我将功能虚拟化,那就更多了
Abnormal temination(Segmentation fault in gcc)
Run Code Online (Sandbox Code Playgroud)
我知道很多都是依赖于实现的,但是如果有人可以对任何实现有所启发,或者只是给出一个概述它会非常好.
好吧,我认为这段代码和程序输出可以自我解释:
#include <iostream>
#include <string>
using namespace std;
class Test
{
public:
void Not_Static(string args)
{
cout << args << endl;
}
};
int main()
{
Test* Not_An_instance = nullptr;
Not_An_instance->Not_Static("Non-static function called with no object?");
cin.ignore();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
程序输出:
没有对象调用的非静态函数?
为什么会这样?
在构造函数内部,允许调用非虚拟成员函数.
从这个事实可以看出,以下代码是明确定义的吗?
struct A {
void foo { std::cout << "Hi there! My address is: " << this; }
};
A * a = nullptr;
a->foo ();
Run Code Online (Sandbox Code Playgroud)
回答?
借助评论中给出的一些链接以及链接页面中给出的链接,我现在认为答案可以在例如
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3035.pdf
§3.8标准杆 5,p.66:
"在对象的生命周期开始之前,但在对象将占用的存储空间被分配之后... [t]如果指针用于访问非静态数据成员,则程序具有未定义的行为或者调用对象的非静态成员函数"
如果根本没有分配存储,那么调用成员函数应该更加未定义.
我想这里有一个很重要的原因可以让它定义为未定义:https://stackoverflow.com/a/3257755/1419315
class A {
public:
void foo() { cout << "Work";}
void bar() { this->foo(); }//new edit, works too!
};
class B {
private:
A *a; //never initialized
public:
A& getA() {
return *a;
}
};
void SomeFunction() {
B *b = new B();
B& bRef = *b;
bRef.getA().bar();//edited
delete b;
}
Run Code Online (Sandbox Code Playgroud)
我调用SomeFunction()而没有初始化"a",它仍然正确打印"工作".我不明白为什么,它应该有分段故障拯救!
在我使用C++的早期,我似乎记得你可以使用NULL指针调用成员函数,并在成员函数中检查它:
class Thing {public: void x();}
void Thing::x()
{ if (this == NULL) return; //nothing to do
...do stuff...
}
Thing* p = NULL; //nullptr these days, of course
p->x(); //no crash
Run Code Online (Sandbox Code Playgroud)
这样做可能看起来很愚蠢,但是当编写递归函数来遍历数据结构时,这绝对是很棒的,导航很容易进入NULL的盲道; 导航功能可以在顶部对NULL进行单一检查,然后轻松地调用自己尝试深入导航而不会乱丢代码并进行额外检查.
至少根据g ++,自由(如果它曾经存在)已被撤销.编译器警告它,如果编译优化,它会导致崩溃.
问题1:C++标准(任何风格)是否禁止使用NULL?或者g ++只是在我面前?
问题2.更哲学,为什么?'这'只是另一个指针.指针的荣耀在于它们可以是nullptr,这是一个有用的条件.
我知道我可以通过创建静态函数来解决这个问题,将第一个参数传递给数据结构的指针(hellllo Days of C),然后检查指针.我很惊讶我需要.
编辑:为了提出答案,我希望看到关于为什么不允许这样做的标准的章节和经文.请注意,我在NO POINT处的示例取消引用NULL.这里没有什么是虚拟的,并且p被复制到"参数this"但在使用之前被检查.没有任何差别!因此,取消引用NULL不能用作UB的声明.
人们对*p做出了下意识的反应,并假设如果p为NULL则无效.但确实如此,证据就在这里:http: //www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232 事实上,当一个指针p令人惊讶时,它会调出两个案例有效为*p:当p为null或p指向一个元素超过数组末尾时.你必须做的就是使用*p的值......除了获取它的地址.&*p其中p == nullptr表示任何指针类型p都有效.可以指出p-> x()实际上是(*p).x(),但在一天结束时转换为x(&*p)并且形成得非常好且有效.对于p = nullptr ...它只是变成x(nullptr).
我认为我的辩论应该与标准界有关; 他们急于削弱空引用的概念,他们的措辞不清楚.因为这里没有人要求p-> x()是UB而不试图要求它是UB,因为*p是UB; 并且因为*p绝对不是UB,因为x()的任何方面都没有使用引用的值,我将把它归结为g ++对标准歧义的超越.使用静态函数和额外参数的绝对相同的机制已经很好地定义了,所以它不会停止我的重构工作.考虑撤回的问题; 可移植代码不能假设这个== nullptr会工作但是有一个可移植的解决方案,所以最后它没关系.
考虑以下代码:
int main()
{
struct EmptyStruct{
void nonstatic_mf() const { std::cout <<"EmptyStruct\n"; }
};
EmptyStruct *esptr = nullptr;
esptr->nonstatic_mf();
}
Run Code Online (Sandbox Code Playgroud)
这是一个合法的 C++(它似乎在 gcc 和 clang 中工作)?
我写了一个非常简单的代码.在动态创建一个对象,然后我删除该对象并将其分配给零.之后我访问该对象的成员函数,但我的程序不会崩溃,而是返回值.
class MyClass
{
public:
MyClass() {}
int funct() { return 0; }
};
int main()
{
MyClass *mc = new MyClass;
delete mc;
mc = 0;
// The program should crash here as I've set mc to zero after deleting
// it. But it returns the value.
int retVal = mc->funct();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
根据我对new的理解,删除和赋值为零,这段代码应该崩溃,或者给出异常.
我正在经历shared_ptr并遇到了这个问题。
class A
{
public:
A() { cout << "In constructor" << endl; }
~A() { cout << "Destructor" << endl; }
void fun() { cout << "In fun... " << endl; }
};
int main()
{
shared_ptr<A> a;
a->fun();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是-有趣的是...
我想了解这是如何给上面的输出。
在进一步的实验中,如果存在成员变量并在该函数中使用它,则会抛出SIGSEGV。
class A
{
public:
A() { cout << "In constructor" << endl; }
~A() { cout << "Destructor" << endl; }
void fun() { a = 5 ; cout << "In fun... " << …Run Code Online (Sandbox Code Playgroud) 请找到我从https://www.geeksforgeeks.org/auto_ptr-unique_ptr-shared_ptr-weak_ptr-2/获取的用于测试智能指针的代码。
// C++ program to demonstrate shared_ptr
#include <iostream>
#include <memory>
class A {
public:
void show()
{
std::cout << "A::show()" << std::endl;
}
};
int main()
{
std::shared_ptr<A> p1(new A);
std::cout << p1.get() << std::endl;
p1->show();
std::shared_ptr<A> p2(p1);
p2->show();
std::cout << p1.get() << std::endl;
std::cout << p2.get() << std::endl;
// Returns the number of shared_ptr objects
// referring to the same managed object.
std::cout << p1.use_count() << std::endl;
std::cout << p2.use_count() << std::endl;
// Relinquishes ownership of p1 …Run Code Online (Sandbox Code Playgroud) 我知道共享指针意味着共享相同的内存。但是,如果我的共享指针指向的元素不是另一个共享指针内存中的第一个元素怎么办?
考虑一个原始指针示例:
int* array = new int[10];
int* segment = &array[5];
Run Code Online (Sandbox Code Playgroud)
array我可以用共享segment指针做同样的事情吗?在这种情况下他们会计算参考文献吗?