std::make_shared、std::unique_ptr和移动构造函数

12

以下代码可以使用clang 3.0/libc++编译:

#include <memory>

class Foo
{
public:
    Foo()
        : mem_(new int(10))
    {
    }
    std::unique_ptr<int> mem_;
};

int main()
{
    auto foo = std::make_shared<Foo>();
    return 0;
}

但这个不行(添加了std::string参数):

#include <memory>
#include <string>

class Foo
{
public:
    Foo(const std::string& s)
        : mem_(new int(10))
    {
    }
    std::unique_ptr<int> mem_;
};

int main()
{
    auto foo = std::make_shared<Foo>("aaa");
    return 0;
}

Clang报告了一个已删除构造函数的使用情况。对我来说,这没有意义,因为std::make_shared不应该复制Foo实例,唯一会触发std::unique_ptr的(已删除)复制构造函数的调用的是其他方法。

但是令人惊讶的是,只要我明确定义移动构造函数,它就可以编译。

#include <memory>
#include <string>

class Foo
{
public:
    Foo(const std::string& s)
        : mem_(new int(10))
    {
    }
    Foo(Foo&& other)
        : mem_(std::move(other.mem_))
    {
    }
    std::unique_ptr<int> mem_;
};

int main()
{
    auto foo = std::make_shared<Foo>("aaa");
    return 0;
}

现在,问题如下:

  1. 为什么第一个示例可以编译而第二个示例不能?
  2. std::make_shared 在构造对象时是否可以复制/移动对象?
  3. 为什么添加移动构造函数可以解决问题?我不记得添加非默认构造函数应该会禁止隐式移动构造函数。

编辑:经过检查,所有示例似乎都可以在gcc 4.5.1(通过ideone.com)上编译,我怀疑这是clang/libc++的错误,但问题2和3仍然存在,另外我想知道哪个编译器更加“正确”。


1
我认为永远不会提供隐式移动构造函数。 - parapura rajkumar
@parapura rajkumar (1) 移除 unique_ptr 会使其消失(即使有非默认构造函数),(2) 根据最新措辞,隐式移动构造函数仍然被定义:http://mmocny.wordpress.com/2010/12/09/implicit-move-wont-go/ - Alex B
@parapurarajkumar:确实,我记得曾经读过讨论,隐式移动构造函数是一件坏事,并且应该从标准中删除。但是,我不知道故事的结局。 - Alexandre C.
@Joachim,不,我确实是指int(10),这只是一个例子,在这种情况下它并不相关,你可以用任何其他东西来替换它。 - Alex B
1
@Cubbi:clang 最近实现了隐式移动。您可能需要使用显式删除的复制构造函数来禁用它,以触发症状。 - Howard Hinnant
显示剩余3条评论
1个回答

21
为什么第一个示例可以编译,但是第二个不行?
这是一个libc++的漏洞。我正在修复这个问题...
std::make_shared在构造对象时可以进行复制/移动吗?
不,我认为它不能。
为什么添加移动构造函数可以解决问题?我不记得添加非默认构造函数应该抑制隐式移动构造函数。
在您使用的clang版本中,隐式移动构造函数尚未实现。
更新
已修复:http://llvm.org/bugs/show_bug.cgi?id=11616

6
哇!一个小时就处理完了!所以如果我们在clang/libc++中发现其他bug,我们可以直接在Stackoverflow上发布它们来督促你及时修复吗? - deft_code
3
我认为霍华德足够正直,可以修复漏洞,而不需要受到羞辱的压力。;-] - ildjarn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接