仅在某些条件下创建对象,否则返回nullptr

时间:2012-03-09 14:45:21

标签: c++ smart-pointers idioms

我只想在应用某些条件时创建对象,否则重新调整nullptr。这就是我在Delphi(2009 +)中的表现:

function GetGen(n : integer) : Generics.Collections.TList<Integer>;
var
i : integer;
begin
  result := nil;
  if n > 0 then begin
      result := Generics.Collections.TList<Integer>.Create;
      for i := 0 to n - 1 do result.Add(i);
  end;
end;

procedure TestGenList(n : integer);
var
   aInt : integer;
   aGen : Generics.Collections.TList<Integer>;
begin
   aGen := GetGen(n);
   if aGen = nil then begin
      WriteLn('No generic created!');
      Exit;
   end;
   WriteLn(Format('Size: %d', [aGen.Count]));
   for aInt in aGen do Write(Format('%d ', [aInt]));
   aGen.Free; //will clear integers
end;

procedure TestGen
begin
    TestGenList(0);
    Readln;
    TestGenList(5);
    Readln;
end.

这就是我在C ++中的表现:

unique_ptr<vector<int>> GetUniquePrtVec(int n){
    if (n < 1) return(nullptr); //create only if correct input is given
    unique_ptr<vector<int>> result (new vector<int>);
    for (int i = 0 ; i != n; i++){
        result->push_back(i);
    }
    return(move(result));
}

void TestPtrVec(int n){
    unique_ptr<vector<int>> vec = GetUniquePrtVec(n);
    if (vec == nullptr){
        cout << "No vector created" << endl;
        return;
    }
    cout << endl << vec->size() << endl;
    for_each(vec->begin(), vec->end(), [](int n){cout << n << " " << endl;});
    vec->clear(); //clear vector
    vec.reset(nullptr);
}

void testVec3(){
    TestPtrVec(0);
    TestPtrVec(5);
}

我的问题是关于正确的习语。你们,经验丰富的C ++程序员(因为我是初学者,只是学习语言),你会这样做吗?如果没有,那你会怎么做?

感谢。

5 个答案:

答案 0 :(得分:1)

我个人认为,有一个指向向量的指针有点必要,它看起来就好像你只能返回一个空向量甚至抛出一个无效的参数错误。整个null返回值有点像黑客,现在你必须管理一些内存。

我个人宁愿看

std::vector<int> get_vec(int n){
    std::vector<int> result;
    if(n < 1) return result;
    result.reserve(n);
    for (int i = 0 ; i != n; i++){
        result.push_back(i);
    }
    return result; 
}

std::vector<int> get_vec(int n){
    if(n < 1) throw std::invalid_argument("n must be greater than 1");
    std::vector<int> result;
    result.reserve(n);
    for (int i = 0 ; i != n; i++){
        result.push_back(i);
    }
    return result;
}


void test(int n){
    try{
    std::vector<int> vec = get_vec(n);
    catch(const std::exception& e)
    {
        std::cerr << "No vector created: " << e.what() << std::endl;
        return;
    }

//etc. .  .

答案 1 :(得分:1)

恕我直言,对你的例子来说,最简单的方法就是简单地按值返回std::vector,如果输入无效,则只返回一个空的。

std::vector<int> get_vec(int n){
  std::vector<int> ret;
  for(unsigned i=0; i < n; ++i)
    ret.push_back(i);
  return ret; // will be empty for (n < 1)
              // and will be moved if (n >= 1)
}

您需要学习的一件事:如果返回局部变量,则不需要显式std::move。只是按价值回报。如果可以复制省略,它就会这样做(RVO / NRVO)。如果由于某种原因它不能,它会首先尝试在复制之前将其移出。但请注意,局部变量的成员不会自动移动,也就是

struct object{ std::vector<int> member; };

std::vector<int> foo(){
  object o;
  // ...
  return o.member; // no move, no copy elision, plain old copy
}

现在,您的第二个功能也可以改进和减少:

void try_vec(int n){
  auto vec = get_vec(n); // will elide copy or simply move
  for(auto& x : vec) // will not loop if vector is empty
    std::cout << x << ' '; // why space and newline?
  std::cout << "\n"; // don't use std::endl, it also flushes the stream
}

从原来的功能:

vec->clear(); //clear vector
vec.reset(nullptr);

不需要,这就是智能指针和资源管理容器的全部原因。当他们超出范围时,他们会破坏他们拥有的东西。

答案 2 :(得分:1)

似乎你需要的是像boost::optional这样的东西。以下是其用法示例:

optional<char> get_async_input()
{
    if ( !queue.empty() )
        return optional<char>(queue.top());
    else return optional<char>(); // uninitialized
}

void receive_async_message()
{
    optional<char> rcv ;
    // The safe boolean conversion from 'rcv' is used here.
    while ( (rcv = get_async_input()) && !timeout() )
        output(*rcv);
}

有关更多信息,请参阅boost documentation.

答案 3 :(得分:-1)

使用异常或键入擦除,返回NULL是C语言的做法,而不是C ++方式。

你也使用移动语义,但你没有返回一个r值,它不会那样。

答案 4 :(得分:-1)

我对这种语法不太感兴趣,但我觉得它看起来不错。但是,为什么不使用通常的c +语法指针?

vector<int> GetUniquePrtVec(int n)
{
    if (n < 1) 
        return null;

    vector<int>* result = new vector<int>;
    for (int i = 0 ; i != n; i++){
        result->push_back(i);
    }
    return (result);
}

虽然我从未使用过矢量指针。通常,当我创建一个向量时,我会通过引用将它传递给函数,如下所示:

vector<int> myVec;
bool bSuccess = PopulateVec(n, myVec);

vector<int>* PopulateVec(int inNum, vector<int>& inVec)
{
    if (inNum< 1)
        return false;

    for (int i = 0 ; i != inNum; i++)
    {
        inVec->push_back(i);
    }

    // inVec is "returned" by reference
    return true
}