函数返回类型:指针,参考或其他?

时间:2015-11-20 11:28:40

标签: c++ c++98

让我们假设我总是需要函数的direkt返回类型为错误代码(计算成功或失败),然后我将返回一些参数作为参数。将它们定义为引用(并在空前创建它们)或更好地返回指针是否更好?

编辑:我应该更精确:错误代码是强制性的,因为我必须坚持给出编码指南。

可能性A:

ErrorCode func( some_parameters ... , ReturnType & result)
...
ReturnType result; // empty constructor, probably not good practice
func( some_parameters ..., result)

可能性B:

ErrorCode func( some_parameters ... , ReturnType * result){
    ...
    result =  new ReturnType(...)
    ...
}
...
ReturnType * result; // void pointer
func( some_parameters ..., result)
...
delete result; // this is needed if I do not use a smart pointer

更好:也许你有更合适的解决方案?

编辑:请说明您使用的是哪种标准,因为不幸(指南)我必须坚持使用C ++ 98.

4 个答案:

答案 0 :(得分:3)

我会做以下(一般情况下)

1。)抛出异常而不是返回错误代码

如果这是不可能的(出于任何原因)

2。)直接返回指针(raw或std :: unique_ptr)并返回nullptr失败

如果返回类型必须是bool,则返回的所有对象都是(指针/堆分配)

3.)返回你的错误代码(bool或enum类)并接受所有要初始化的对象的引用参数(必须有对象)和指向可以选择创建/初始化的对象的指针

如果无法事先为调用创建对象(例如因为它不是默认构造的)

4。)传递对指针(raw或std :: unique_ptr)的引用或指向指针的指针,然后由函数填充

如果你只有一个真/假的返回代码,那么

std :: optional(或类似的)可能是一个选项。

我不喜欢返回std :: pair或std :: tuple,因为如果你必须开始使用.first / .second或std :: get<>(),它会让你的代码看起来很烦人访问您的不同退货类型。使用std :: tie()可以减少这一点,但它(但)使用起来并不舒服,并且阻止使用const。

示例:

std::unique_ptr<MyClass> func1() { /* ... */ throw MyException("..."); }

std::unique_ptr<MyClass> func2() { /* ... */ }

ErrorCode func3(MyClass& obj, std::string* info = nullptr) { /* ... */ }

ErrorCode func4(std::unique_ptr<MyClass>& obj) { /* ... */ }

int main()
{
     try 
     {
          auto myObj1 = func1();
          // use ...
     }
     catch(const MyException& e)
     {
          // handle error ...
     }

     if(auto myObj2 = func2())
     {
          // use ...
     }

     MyClass myObj3;
     std::string info;
     ErrorCode error = func3(myObj3, &info);
     if(error == ErrorCode::NoError)
     {
          // use ...
     }

     std::unique_ptr<MyClass> myObj4;
     ErrorCode error = func4(myObj4);
     if(error == ErrorCode::NoError)
     {
          // use ...
     }
 }

编辑:一般情况下建议保持API的一致性,所以如果你已经有一个中型或大型代码库,它会使用一种或另一种策略,你应该坚持这一点(如果你没有充分的理由)不要)。

答案 1 :(得分:2)

这是std::optional的典型示例。可悲的是,它还没有,所以你想使用boost::optional

这假设结果总是&#34;成功结果&#34;或&#34;失败而没有结果&#34;。如果您的结果代码更复杂,您可以返回
using (PrincipalContext ad = new PrincipalContext(contextType, adserviceName, adContext, ContextOptions.SimpleBind, username, password)) { UserPrincipal u = new UserPrincipal(ad) {Name = "*"}; PrincipalSearcher search = new PrincipalSearcher { QueryFilter = u }; // get the underlying "DirectorySearcher" DirectorySearcher ds = search.GetUnderlyingSearcher() as DirectorySearcher; if(ds != null) { // set the PageSize, enabling paged searches ds.PageSize = 500; } foreach (var principal in search.FindAll()) { //do something } }

答案 2 :(得分:2)

对所有返回信息使用返回值将是一种好方法。例如:

std::tuple<bool, ReturnType> func(input_args....)

或者,如果状态代码是布尔值,则返回类型可以是std::optional(或其前身),空optional表示函数失败。

但是,如果计算通常应该成功,并且只在极少数情况下失败,那么返回ReturnType并抛出异常以指示失败将是更好的风格。

当代码没有对每个返回值进行错误检查时,代码更容易阅读;但要成为健壮的代码,需要在某处或其他地方检查这些错误。例外情况可让您在一个地方处理各种异常情况。

答案 3 :(得分:0)

不知道它是否适用于您的情况,但如果您只有两个状态返回类型,那么可能只是从您的函数返回指针然后测试它是否为nullptr?