C++ 为不应该发生的事情获取未定义的行为';不要有不确定的行为 类示例 { 公众: int*ptr; 样本(int i) { ptr=新的整数(i); } ~Sample() { 删除ptr; } void PrintVal() { 您的代码确实有未定义的行为。但是让我们从头开始 class Sample { public: int *ptr; Sample(int i) { ptr = new int(i); } ~Sample() { delete ptr; } void PrintVal() { cout << "The value is " << *ptr; } }; void SomeFunc(Sample x) { cout << "Say i am in someFunc " << endl; } int main() { Sample s1 = new Sample(10); SomeFunc(s1); s1.PrintVal(); }

C++ 为不应该发生的事情获取未定义的行为';不要有不确定的行为 类示例 { 公众: int*ptr; 样本(int i) { ptr=新的整数(i); } ~Sample() { 删除ptr; } void PrintVal() { 您的代码确实有未定义的行为。但是让我们从头开始 class Sample { public: int *ptr; Sample(int i) { ptr = new int(i); } ~Sample() { delete ptr; } void PrintVal() { cout << "The value is " << *ptr; } }; void SomeFunc(Sample x) { cout << "Say i am in someFunc " << endl; } int main() { Sample s1 = new Sample(10); SomeFunc(s1); s1.PrintVal(); },c++,C++,这是这一行发生的情况: 堆上分配了一个Sample对象,并且new表达式返回指向它的指针,即Sample* 您不能将Sample*分配给Sample类型的变量。但是Sample具有允许从int隐式构造的构造函数。如果使用-fpermissive编译器选项(提示:不要!),编译器允许将指针隐式转换为整数–毕竟,指针只是一个内存地址,也称为数字 因此,s1是通过将堆Sample对象的内存地址解释为一个整数(如果sizeof(Sample*)>sizeof(int),则将其截断)来构造的。该值最终为*

这是这一行发生的情况:

  • 堆上分配了一个
    Sample
    对象,并且
    new
    表达式返回指向它的指针,即
    Sample*
  • 您不能将
    Sample*
    分配给
    Sample
    类型的变量。但是
    Sample
    具有允许从int隐式构造的构造函数。如果使用
    -fpermissive
    编译器选项(提示:不要!),编译器允许将指针隐式转换为整数–毕竟,指针只是一个内存地址,也称为数字
  • 因此,
    s1
    是通过将堆
    Sample
    对象的内存地址解释为一个整数(如果
    sizeof(Sample*)>sizeof(int)
    ,则将其截断)来构造的。该值最终为
    *(s1.ptr)
  • 重申关键点:在这一行中,您没有实例化一个
    Sample
    对象,而是实例化两个。Bug 1:在堆上创建的对象永远不会被删除。这是内存泄漏

    Sample s1 = new Sample(10);
    
    Sample
    中没有任何内容阻止编译器生成默认的复制构造函数和默认的复制赋值运算符。重要提示:指针的“default”表示复制指针,而不是指针后面的对象。因此:

  • s1
    被复制以调用
    SomeFunc()
    。该副本在函数中以
    x
    的形式提供。由于默认指针copy
    s1
    x
    都指向相同的
    int
    对象
  • x
    在函数结束时超出范围,析构函数运行并删除
    int
    对象
  • 我们还没有完全确定,但我们正在接近

    SomeFunc(s1);
    
    函数试图访问指针后面的
    int
    对象,但该对象已被删除。
    s1.ptr
    是一个悬空指针。错误2:取消对悬空指针的引用是未定义的行为


    以及所有这一切,因为它是int型转换的一个看似无害的隐式指针……这就是为什么它默认是编译器错误的原因,至少在非古编译器中是这样的。< /P>我看不出这是如何编译的,但是你确实需要一个拷贝构造函数和赋值操作符——参见3的规则。C++不是java,BTW指针和O有一个区别。对象。

    Sample*s1=新样本(10)
    您需要遵循。当您复制对象时,两个实例现在拥有相同的动态分配的
    int
    ,并且都试图销毁它。如果您有未定义的行为,并且您不期望有未定义的行为,那么您对代码没有未定义行为的假设几乎总是不正确的。
    s1.PrintVal();