小编Har*_*nak的帖子

未定义的行为

我正在对C++进行一些模拟,我遇到了一个奇怪的问题.我有以下函数返回double的向量:

vector<double> processSimulation(int Q){
//do things
vector<double> output;
output.push_back(mean);
output.push_back(variance);
return output;
}
Run Code Online (Sandbox Code Playgroud)

总的来说,我有以下几点:

//define Q
vector<double>::iterator it = processSimulation(Q).begin();
double mean = *it;
double variance = *(it+1);
Run Code Online (Sandbox Code Playgroud)

问题是我得到了一个错误的数字(e-305)和方差的正确数字.我试图自己解释这种行为,我认为这可能是由未定义的行为引起的,因为迭代器指向函数中的旧向量,现在已超出范围并且不再存在.我对么? 可能我只是幸运,方差是正确的,因为它也可能是错的.

我将代码更改为

vector<double> output = processSimulation(Q);
vector<double>::iterator it = output.begin();
//same as before
Run Code Online (Sandbox Code Playgroud)

它工作得很好,所以这加强了我的创作.

此外,我注意到一个调试器很奇怪:当试图找出发生了什么(在修复代码之前)时,我通过调试查看了均值和方差的值,它们都是错误的.虽然,当我运行程序时,只有平均值是错误的(我已经尝试了很多次并且它总是:在调试时都错了,在运行时意味着错误和方差正确).这里发生了什么?

Java问题:嗯,我遇到的这个问题真的很烦我,因为经常在Java中,为了缩短事情,我没有定义新对象,而是直接在返回该对象的函数上使用方法(如本例所示) .虽然,我从来没有遇到任何问题.我是否一直在做无意识的事情(幸运的是)?或者只是在Java中没有这样的行为存在,因为应该返回对象的函数实际上返回指向它们的指针而真正的对象总是在堆中(并且在没有引用它们时被包围)?

希望你能澄清我的疑惑!

c++ java undefined-behavior

3
推荐指数
1
解决办法
225
查看次数

返回一个对象:值、指针和引用

我知道这可能已经被问过,并且我已经查看了其他答案,但我仍然无法完全理解这一点。我想了解以下两个代码之间的区别:

MyClass getClass(){
return MyClass();
}
Run Code Online (Sandbox Code Playgroud)

MyClass* returnClass(){
return new MyClass();
}
Run Code Online (Sandbox Code Playgroud)

现在假设我在 main 中调用这些函数:

MyClass what = getClass();
MyClass* who = returnClass();
Run Code Online (Sandbox Code Playgroud)
  1. 如果我明白这一点,在第一种情况下,在函数作用域中创建的对象将具有自动存储,即当您退出函数作用域时,其内存块将被释放。另外,在释放此类内存之前,返回的对象将被复制到我创建的“what”变量中。因此该对象将只存在一份副本。我对么?

    1a. 如果我是对的,为什么需要 RVO(返回值优化)?

  2. 在第二种情况下,对象将通过动态存储进行分配,即即使在函数范围之外它也会存在。所以我需要delete在上面使用 a 。该函数返回指向该对象的指针,因此这次没有进行复制,并且执行 delete who 将释放先前分配的内存。我(希望)是正确的吗?

  3. 我也明白我可以做这样的事情:

    MyClass& getClass(){
    return MyClass();
    }
    
    Run Code Online (Sandbox Code Playgroud)

    然后在主要部分:

     MyClass who = getClass();
    
    Run Code Online (Sandbox Code Playgroud)

    通过这种方式,我只是告诉“谁”与函数中创建的对象是同一个对象。不过,现在我们已经超出了函数范围,因此该对象不一定再存在。所以我觉得应该避免这种情况,以免造成麻烦,对吧?(这同样适用于

    MyClass* who = &getClass();
    
    Run Code Online (Sandbox Code Playgroud)

    这将创建一个指向局部变量的指针)。

额外问题:我认为到目前为止所说的一切在返回时也是正确的vector<T>(例如,vector<double>),尽管我错过了一些片段。我知道向量是在堆栈中分配的,而它包含的内容在堆中,但使用vector<T>::clear()足以清除此类内存。现在我想遵循第一个过程(即按值返回向量):当复制向量时它包含的对象也将被复制;但退出函数作用域会破坏第一个对象。现在我拥有的原始对象不包含在任何地方,因为它们的向量已被破坏,并且我无法删除仍在堆中的此类对象。或者也许 aclear()是自动执行的?

我知道我可能会纠正这些主题(特别是矢量部分)的一些误解,所以我希望你能帮我澄清它们。

c++ vector pass-by-reference pass-by-value pass-by-pointer

2
推荐指数
1
解决办法
2093
查看次数

适当使用断言和例外

我已经阅读了一些内容,试图弄清楚何时适当地使用断言和异常,但是我仍然缺少大局.可能我只需要更多的经验,所以我想带一些简单的例子来更好地理解我应该使用什么情况.

示例1:让我们从无效值的经典情况开始.例如,我有以下类,其中两个字段必须为正数:

class Rectangle{
    private int height;
    private int length;

    public int Height{
        get => height;
        set{
            //avoid to put negative heights
        }
    }
    //same thing for length
}
Run Code Online (Sandbox Code Playgroud)

让我说一下,我不是在讨论如何在这个例子中处理用户输入,因为我可以为此做一个简单的控制流程.虽然,我面临的想法是,在其他地方可能会出现一些意外错误,我希望能够检测到这一点,因为我不想要一个带有invald值的对象.所以我可以:

  • Debug.Assert如果发生这种情况,请使用并停止程序,这样我就可以纠正可能出现的错误.
  • 扔一个ArgumentOutOfRangeException基本上做同样的事情?这感觉不对,所以只有当我知道我要在某个地方处理它时我才应该使用它.虽然,如果我知道在哪里处理异常,我不应该解决它所在的问题吗?或者它可能意味着可能发生的事情,但你不能直接在你的代码中控制,比如用户输入(可以处理,没有例外,但可能是别的东西不能)或加载数据?

问题:我是否明白了断言和例外的含义?另外,请举例说明处理异常是否有用(因为之前你无法控制的东西)?除了我提到的情况之外,我无法弄清楚还有什么可以发生,但我显然仍然缺乏经验.
为了扩展我的问题:我可以想出为什么可以抛出异常的各种原因,比如a NullReferenceException,a IndexOutOfBoundsException,IO异常,DirectoryNotFoundException或者FileNotFoundException等等.虽然,我无法弄清楚处理它们变得有用的情况,分开从简单地停止程序(在这种情况下,不应该使用断言?)或给出一个简单的消息,问题发生在哪里.我知道即使这是有用的,例外也意味着对"错误"进行分类并提供如何解决它们的线索.虽然,这是一个简单的消息,它们真的对它们有用吗?这听起来很可疑,所以我会坚持"我从来没有遇到过适当的情况,"经验的原因"口头禅.

示例2:现在让我们使用第一个示例来讨论用户输入.正如我所预料的那样,我不会仅仅使用例外来检查值是否为正,因为这是一个简单的控制流程.但是如果用户输入一个字母会发生什么?我应该在这里处理一个例外(可能很简单ArgumentException)并在catch块中给出一条消息吗?或者也可以通过控制流程来检查(检查输入是否类型int,或类似的东西)?

感谢任何能够消除我挥之不去的怀疑的人.

c# debugging assert exception

1
推荐指数
1
解决办法
195
查看次数