2012-03-09 13 views
1

いくつかの条件が適用される場合にのみオブジェクトを作成したい場合はnullptrを再実行します。これは私がデルファイ(2009+)でそれを行うだろうかです:何らかの条件がある場合のみオブジェクトを作成し、それ以外の場合はnullptrを返します。

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++プログラマ(私は初心者で、言語を学ぶだけです)、このようにしますか?もしそうでなければ、あなたはどうやってそれをしますか?

ありがとうございました。

+0

あなたが書いたC++コードから初心者ではないようですね! – iammilind

+0

ありがとう、私はプログラミングではなく、C++の初心者です:)私のジレンマを具体化するには、nullptrを調べるか、vec ptr変数を別の関数のどこかに空のベクトルを指すようにしますか? – Mihaela

+2

これは文脈から答えるのは難しいです。 'GetUniquePtrVec'関数は無用に聞こえます(必要な場所にベクターを作るだけです)。さらに、 'vector'はすでに動的コンテナクラスであるため、動的管理の余分な層に包むことは非常に珍しいことです。個人的には、ここでは符号なし整数がより良いアプローチであると推測します。 –

答えて

1

IMHO、あなたの例のための最善の方法は、単に値でstd::vectorを返し、単に場合は、空の1を返すようになり見るでしょう入力が無効です。

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)。それが何らかの理由でできない場合、コピーする前に最初に移動しようとします。

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 
} 

そして、あなたの本来の機能から:

別名

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

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

今、あなたの第二の機能も向上して低減することができ、ローカル変数のメンバーが自動的に移動されないこと、しかし、注意してください

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

これは、スマートポインタとリソース管理コンテナのすべての理由です。彼らは彼らが範囲外に出たときに彼らが所有しているものを破壊するでしょう。

+0

ありがとう、私はいつもパスカルで物事をクリアします。それを知らせて、範囲に焦点を合わせるだけです。 – Mihaela

-1

NULLを返す例外や型消去を使用すると、C++の方法ではなく、処理を行うCの方法です。

また、移動意味を使用していますが、r値を返さない場合は、そのようには機能しません。

+1

移動セマンティクスについてのあなたの考えは間違っています。戻り値の型がrvalue参照であれば*特に悪い*でしょう。そして値を返すことは、正確には移動セマンティクスを使用する点です。また、 'nullptr'を返すことはC++では完璧です。*ポインタを使う必要がある場合は*です。それ以外の場合、 'boost :: optional'も素晴らしい候補です。そして、ここでタイプイレージャーが必要でしょうか? – Xeo

1

個人的に私は、ベクトルへのポインタを持つことは少し必要ですが、空のベクトルを返すか、無効な引数エラーを投げることができるかのように見えます。ヌルの戻り値全体はちょっとしたハックです。そのために、いくつかのメモリを管理する必要があります。

私は個人的にはむしろ

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. . . 
+0

result.reserve(n)良い点ですが、私はコピーを避けたかったのです。もし100k要素のベクトルを持っていたら?戻り値(結果)がコピーコンストラクタを呼び出すのではないですか?または私はこれを間違っているのですか? – Mihaela

+0

@Mihaela:はい、コンパイラは最初に*移動*しようとしますが、可能でない場合にのみコピーしようとします。私の答えを見てください。 – Xeo

+0

あなたが使用している@Mihaela私はあなたがC++ 11を持っていると仮定しています。その場合、コピーされずに移動されます。これは、ポインタを交換するような非常に軽量な操作です。実際に 'return std :: move(result);'を置くと、コンパイラが大切なコピーのエリミエーション最適化をやめさせる可能性が高くなります。最終的にリターンはそれのまわりに角かっこを入れる関数ではありません。 – 111111

1

あなたが必要とするものはboost::optionalのようです。 boost documentation.

+0

私はあなたのことを聞いていますが、私はSTLで作業したいと思っています。ありがとう。 – Mihaela

+0

@Mihaela:Boostはステロイドのstdlibです。そして、標準ライブラリ "STL"を呼び出さないでください。その部分は、コンテナ/アルゴリズム/イテレータ/関数オブジェクトのサブパートの名前です。 – Xeo

+0

申し訳ありませんが、標準ライブラリ(STL Mihaela

-1

イムにこの構文を使用して少しunfamilliarを参照してください。詳細については

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); 
} 

、私はそれが私には大丈夫に見えると思います。ここではその使用方法の一例です。しかし、通常の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 
} 
+0

私はあなたがいくつかの問題を抱えているので、あなたのコードを見直すべきだと思います。また、***いいえ***、生のポインタを所有しているのはちょっとしたアイデアです*。それらを使用しないでください。ダイナミックアロケーション*を行う必要がある場合はスマートポインタ*を使用してください。 – Xeo

関連する問題