簡體   English   中英

在向/從函數返回值/參數和類請求的數據傳輸期間是否復制了指向內存的指針?

[英]Are pointers to memory copied during data transfer to/from function return values/arguments and class requests?

假設我具有以下功能(其中mVertexShaderstd::shared_ptr< ID3D11VertexShader >類成員,而mRenderData只是保存其他D3D內容的POD):

void VertexShader::CreateShader( void )
{
    GVertexShader* raw_VertexShader = mVertexShader.get();

    mRenderData->Device->CreateVertexShader(
        mCompiledShader->GetBufferPointer(),
        mCompiledShader->GetBufferSize(),
        NULL,
        &raw_VertexShader
    );

    delete raw_VertexShader;
    raw_VertexShader = NULL;
} 

因為mVertexShader.get()返回原始指針,將刪除raw_VertexShader效果內部的指針mVertexShader.get()或者,當被指向的存儲器來是一樣的,指針本身是完全不同的?

我猜是后者,因此為什么首先要存在引用指針,但是我想確保我有正確的主意。

注意:我目前正在使用MSVC ++,盡管很高興得知MSVC ++和MinGW / GCC的實現方式是否存在重大差異。

注意2:如果我不清楚,我深表歉意–我在這里完全不是指D3D的語義,而是有關內存管理,數據傳輸和動態內存分配的C ++本身語言的語義。 從這個意義上講,我試圖確切地了解從函數返回原始指針時會發生什么。

即,假設mVertexShader正在存儲指向任意VertexShader的簡單原始指針,當我調用其get()方法時,它是否返回一個復制的指針,該指針指向與shared_ptr容器內的引用相同的內存地址,或者它是一個完全新的指針,已經被復制並返回,並且內存指向另一個地址嗎?

實際上,這完全與std::shared_ptr的語義有關。 該語言非常高興地支持以下方法:返回指向對象的指針,創建對象的副本並返回指向該對象的指針,或對對象上的引用計數進行碰撞並返回指向該對象的指針。 您可以根據需要執行所有這些操作。

共享指針上的get方法僅將原始指針返回到對象。 沒有副本。 永遠不要 delete此指針,原因有兩個:

  1. 另一個對象可能具有指向同一對象的共享指針,因此您將從該對象下面刪除該對象。 (這就是共享指針的要點。)

  2. 當最后一個共享指針消失時,該對象將被刪除。 兩次刪除對象是UB,可能會導致代碼崩潰。 (這也是共享指針的要點。)

讓共享指針完成其工作。

請注意,如果調用共享指針上的get ,則應確保將共享指針保留了很長時間,只要您可以使用獲得的原始指針即可。 否則,對象可能會不復存在。 共享指針的邏輯是,只要您在該對象周圍保持至少一個共享指針,該對象就不會被刪除,並且當最后一個此類共享指針消失時,該對象會自動刪除。

這個問題是關於Direct3D的。

(免責聲明:我一生中從未做過任何D3D,我只是在閱讀文檔的基礎上盡力而為,但我想我就在這里!)

您正在調用一個名為CreateVertexShader的方法。 沒關系shared_ptr東西。 您應該像這樣啟動您的方法:

GVertexShader* raw_VertexShader = NULL;  // don't initialize
                                         // with get() or anything like that.
mRenderData->Device->CreateVertexShader(
    mCompiledShader->GetBufferPointer(),
    mCompiledShader->GetBufferSize(),
    NULL,
    &raw_VertexShader
);
// The raw_VertexShader will *not* be NULL any more.  It will have the address
// of the shader that was created by CreateVertexShader.

該方法(我假設)將創建一個VertexShader。 它將在內存中所需的任何地方創建它,可能是通過new VertexShaderImplementation(...)或其他方式。 然后,它必須將指向該對象的指針返回給您。 而不是通過返回值返回它,它要求您傳遞一個指向ID3D11VertexShader的指針。 這是在說: “我已經創建了一個新對象。我有它的地址,即指向ID3D11VertexShader的指針。但是,為了讓我給您地址,我需要您告訴我在哪里寫下它。指向ID3D11VertexShader的指針的地址,並將其寫在其中。即,給我一個指向ID3D11VertexShader的指針。

這說明了CreateVertexShader使用**ID3D11VertexShader作為其參數的事實。 注意兩個* s。

那么,shared_ptr與這有什么關系?

(簡單的答案:沒有!您可能會忘記了shared_ptr,但這不是現代的C ++。)

當CreateVertexShader返回時,該指針不屬於任何共享指針。 您必須先獲取指針(即運行CreateVertexShader ),然后才能將該對象的所有權提供給shared_ptr。

您要嘗試做的是安排D3D直接將指針直接“塞入”您的shared_ptr 但這行不通。 您需要先讓CreateVertexShader “返回”其答案, 然后才能將其放入shared_ptr

mVertexShader.reset(raw_VertexShader); // To be called *after* CreateVertexShader

mVertexShader現在擁有該指針,並且它是唯一擁有此指針的shared_ptr 如果那里已經有其他着色器對象,則可以立即將其刪除(取決於它是否是它的最后一個shared_ptr )。


(.. 未完待續 ..)

我將嘗試直接回答可能引起混亂的原因。 我對這句話很感興趣(我的重點是):

...它是否返回一個復制的指針 ,該指針指向與shared_ptr容器內的引用相同的內存地址,或者它是一個完全被復制並返回的全新指針

您在這里誤用了“指針”一詞。 這個片段不清楚:“已經被復制的 全新指針 ”。

指針只是一個地址。 如果您復制地址,則只有該地址的另一個副本。 基礎的VertexShader保持不變。 您有一個VertexShader。 您可以根據需要擁有任意數量的地址(即指針)副本,它不會改變任何內容。

因此,也許您想問:“ get()是否只返回shared_ptr擁有的對象的地址? 或者 ,它會創建Shader對象的副本(然后具有不同的地址),然后返回該對象的地址。復制對象嗎?答案是前者,它只是返回地址,我想您可能已經懷疑了,它返回了地址,但是您必須將其存儲在某個地方,並且這種存儲必然涉及到復制指針。

現在,再次查看新代碼:

GVertexShader* raw_VertexShader = NULL;
mRenderData->Device->CreateVertexShader(
    mCompiledShader->GetBufferPointer(),
    mCompiledShader->GetBufferSize(),
    NULL,
    &raw_VertexShader
);
mVertexShader.reset(raw_VertexShader);

執行此操作后,仍然只有一個VertexShader 它有一個地址。 但是該地址已在兩個地方“寫下”。 件事知道着色器在哪里。 raw_VertexShader變量仍然具有該地址。 該地址的另一個副本內置在mVertexShader

考慮這兩個位置。 您無法安排D3D將其新創建的對象的地址直接寫入mVertexShared 您可以將其寫入到raw_VertexShader ,然后將其復制到其中。

請記住,我們只是在此處復制一個地址。 地址就像廢紙一樣,請考慮您所居住建築物的地址。我們可以讓D3D將其寫在一張紙上,然后將其復制到“特殊” shared_ptr紙上。 僅僅因為我們正在復制地址,並不意味着該建築物正在重復!


在調用CreateVertexShared之后,在rest()之前,您確實知道頂點的地址。 您還知道該地址的存儲位置。 您已將其存儲在raw_VertexShader 這意味着您知道raw_VertexShader的地址-您知道在上面寫有着色器地址的紙的地址。 最后一個地址(即一塊地址)是傳遞給CreateVector的地址。 您說: “有一張紙,我要您創建一個Vertex Shader,然后在其上寫地址。您問哪張紙?我會給您這張紙的地址。” 我們找不到shared_ptr內的紙的地址。 我們確實知道在那張紙上了什么(它有VertexShader的地址),但我們不知道那張紙到底在哪里。


刪除

將刪除raw_VertexShader會影響mVertexShader.get()中的指針,還是在指向的內存相同的同時,指針本身完全不同?

在C / C ++中,您實際上並沒有“刪除”指針。 您只需刪除指針指向的對象。 想象一下一張紙上的房子的地址。 假設您還有另一張地址相同的紙。 現在,如果您調用delete pointer1 ,則將拆除其中一間房屋。 這所房屋將被摧毀,將來可能會在其他地方為其他人提供土地的土地也可以使用。 但是這兩張紙都不會改變。 他們仍將有地址,並且他們將擁有相同的地址。 但這將是一個無效的地址。 shared_ptr將無效,並且您的程序最終將崩潰(甚至更糟!)。

如果需要,可以使用raw_VertexShader=NULL;關閉該函數raw_VertexShader=NULL; 這將簡單地擦除那張紙上的地址。 這可能就是你想要的。 您想對自己說:“ shared_ptr擁有該對象,它應該是我用來訪問着色器的唯一機制。因此,我將保持整潔,並將刪除我擁有的地址的所有備用副本。”

但是應該注意raw_VertexShader=NULL; 什么沒做 這是對的。 我只是將其用作教育工具。 影響內部的shared_ptr的一張紙。

(很抱歉,答案很長,我沒有時間簡短。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM