这个问题是关于 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
这解释了以 a**ID3D11VertexShader
作为参数的事实。注意两个*
s。
那么,shared_ptr 和这个有什么关系呢?
(简单的回答:什么都没有!你可以忘记 shared_ptr,但这不是现代 C++。)
当 CreateVertexShader 返回时,指针不被任何共享指针“拥有”。您必须先获取指针(即 run 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 的地址。你说“有一张纸,我要你创建一个顶点着色器,然后在上面写上它的地址。你问是哪张纸?我给你这张纸的地址。” 我们找不到 shared_ptr 中的那张纸的地址。我们确实知道写的是什么在那张纸上(它有 VertexShader 的地址),但我们不知道那张纸的确切位置。
删除
删除 raw_VertexShader 是否会影响 mVertexShader.get() 中的指针,或者,虽然指向的内存相同,但指针本身却完全不同?
在 C/C++ 中,您并没有真正“删除”指针。您只需删除指针指向的对象。想象一张纸,上面写着房子的地址。想象一下,您有另一张具有相同地址的纸。现在,如果你打电话delete pointer1
,你只会拆除其中一所房子。房子将被摧毁,土地将提供给其他可能想在未来某个时候在那里开店的人。但这两张纸都不会改变。他们仍然会在那里拥有地址,并且他们将拥有相同的地址。但这只是一个无效的地址。shared_ptr 将无效,您的程序最终将崩溃(或更糟!)。
如果需要,您可以使用 关闭该功能raw_VertexShader=NULL;
。这只会从那张纸上删除地址。这可能就是你想要的。您想对自己说“shared_ptr 拥有该对象,它应该是我用来访问着色器的唯一机制。因此,我会整理并删除我拥有的地址的任何备用副本。”
但是应该注意的是,raw_VertexShader=NULL;
它什么也没做。这是对的。我只是将它用作教育工具。它不会影响shared_ptr 内的那张纸。
(对不起,回答太长了,我没有时间做一个简短的回答。)