C++ 为什么我的共享\u ptr能够从原始指针隐式构造?

C++ 为什么我的共享\u ptr能够从原始指针隐式构造?,c++,shared-ptr,C++,Shared Ptr,我正在我的应用程序中的std::shared_ptr下放置一个类,转换现有代码。我的理解是,来自原始指针的shared\u ptr构造函数是显式的(例如),这对我来说非常有意义。然而,我在我的应用程序中看到了一件奇怪的事情,在我看来,构造函数似乎是隐式的。我不明白这怎么可能 首先,我有一个typedef用于我的shared\u ptr类型: typedef std::shared_ptr EidosPropertySignature_CSP 然后我有一些代码,在其中我构造了一个新对象,并将其添加

我正在我的应用程序中的
std::shared_ptr
下放置一个类,转换现有代码。我的理解是,来自原始指针的
shared\u ptr
构造函数是显式的(例如),这对我来说非常有意义。然而,我在我的应用程序中看到了一件奇怪的事情,在我看来,构造函数似乎是隐式的。我不明白这怎么可能

首先,我有一个
typedef
用于我的
shared\u ptr
类型:

typedef std::shared_ptr EidosPropertySignature_CSP

然后我有一些代码,在其中我构造了一个新对象,并将其添加到共享指针的向量中:

std::vector<EidosPropertySignature_CSP> properties;

properties.emplace_back(new EidosPropertySignature(...constructor parameters...));
std::向量属性;
重新放置(新的EidosPropertySignature(…构造函数参数…);

这种编译甚至没有任何警告。我不知道如何–新的EidosPropertySignature的结果是一个
EidosPropertySignature*
,它不应该隐式转换为向量所持有的
EidosPropertySignature\u CSP
,对吗?我非常希望这个构造产生编译错误,正如我所认为的那样。为什么不呢?我有没有办法修改我的方法使之生效?

这里没有隐式转换
emplace_back
将其参数直接转发给元素类型的构造函数以构造新元素:

追加一个类型为
T
的对象,该对象由
std构造​::​前进(​参数)..

因此,
emplace\u back
本质上是一个直接的构造函数调用<另一方面,代码>推回将不起作用,因为这实际上需要转换

在纯粹的概念层面上,隐式转换是指允许在必要时将某种类型的值转换为另一种类型的值,这可能是较长转换序列的一部分。转换是关于建造桥梁。通过隐式转换,您可以告诉编译器:这里有一个从
a
B
的桥梁,您可以使用它四处走动。通过显式转换,您可以说:这是从
a
B
的桥梁,只有在我明确告诉您转到
B
时才使用它;特别是,如果你只是想通过
B
去别的地方,不要使用它。当你写
emplace\u back
时,你明确地说“构造一个元素”
emplace_back
明确表示要创建元素类型的对象。您明确告诉编译器转到
B
。如果您查看以下内容,则
安置回

没有任何隐含的含义:

元素是通过
std::allocator\u traits::construct
构造的,它通常使用placement new在容器提供的位置就地构造元素。参数args。。。作为
std::forward(args)…
转发给构造函数

发动机罩下发生的基本情况是:

new (storage) EidosPropertySignature_CSP(<emplace_back args>)
新(存储)EidosPropertySignature_CSP()
调用的显式构造函数,直接从传递的参数构造元素

元素是通过
std::allocator\u traits::construct
构造的,它通常使用placement new在容器提供的位置就地构造元素

请注意,将元素构造为
::new(static_cast(p))T(std::forward);元素类型的构造函数是
explicit
,与否无关

(强调矿山)

直接初始化比复制初始化更允许:复制初始化只考虑非显式构造函数和非显式用户定义的转换函数,而直接初始化考虑所有构造函数和所有用户定义的转换函数


另一方面,将
shared\u ptr
作为参数类型,当传递原始指针时,必须隐式地将其转换为
shared\u ptr
,这是格式错误的,因为
显式的
转换构造函数不会被考虑在内。

因为使用
emplace\u back
,它不是隐式的

该函数类似于
模板引用emplace\u back(Args&&…Args)
,因此在本例中,您有一个参数,
eidoPropertySignature*
,因此没有问题

然后将使用
std::forward(args)…
调用
std::shared\u ptr
构造函数,该构造函数可以调用显式构造函数

template<class T, class... Args> T construct(Args...args)
{
    return T(std::forward<Args>(args)...);
}
int main()
{
    int *x = new int();
    std::shared_ptr<int> a = x; // error 
    std::shared_ptr<int> b(std::forward<int*>(x)); // OK
    std::shared_ptr<int> c = construct<std::shared_ptr<int>>(x); // OK
}
模板T构造(Args…Args)
{
返回T(标准:正向(参数)…);
}
int main()
{
int*x=新的int();
std::shared_ptr a=x;//错误
std::shared_ptr b(std::forward(x));//确定
std::shared_ptr c=construct(x);//确定
}

正如您自己所说,shared\u ptr有一个接受原始指针的显式构造函数。该构造函数被调用。您为什么希望它不起作用?我不调用显式构造函数。我只是将一个
eidoPropertySignature*
传递给
emplace\u back()
。因此,转换是隐式完成的。或者我不明白构造函数声明为
显式
?这意味着什么?但我确实认为我理解了这一点!:-O我希望必须执行类似
emplace\u back(eidoPropertySignature\u CSP(new…)
emplace\u back(shared\u ptr(new…)
。这不是构造函数的全部要点是明确的吗?@bhaller
emplace\u back
vs
push\u back
的全部要点是
emplace\u back
接受元素类型的构造函数的参数,而不是元素类型的直接实例。从Michael Kenzel下面的回答中,我现在明白了。我将请在下面进一步说明他的答案