私有构造抑制使用布设的[_back](),以避免移动(Private constructor inh

2019-06-26 04:34发布

考虑下面的代码:

#include <vector>

class A
{
public:    
    A(A&&);  // somewhat expensive

    static std::vector<A> make_As()
    {
        std::vector<A> result;
        result.push_back(A(3));
        result.push_back(A(4));
        return result;
    }

private:
    A(int);  // private constructor
};

由于A的移动构造函数是比较昂贵的(无论何种原因),我想避免调用它,使用emplace_back()代替:

#include <vector>

class A
{
public:    
    A(A&&);  // somewhat expensive

    static std::vector<A> make_As()
    {
        std::vector<A> result;
        result.emplace_back(3);
        result.emplace_back(4);
        return result;
    }

private:
    A(int);  // private constructor
};

不幸的是, emplace_back()实际的构造函数的调用由标准库,这是不够的荣幸能够调用的东西做A “私有构造函数。

我认识到,有可能是什么可以搞定这个问题,但尽管如此我觉得既然调用emplace_back()成员中出现A ,他们应该能够调用私有构造函数。

有没有这方面的任何解决方法?

我能想到的唯一的事情就是添加一个好友,申报A ,但需要进行精确的类A的朋友(也就是实际尝试调用构造函数的类)是实现特定的(例如为GCC是__gnu_cxx::new_allocator<A> )。 编辑 :刚刚意识到这样的朋友声明会允许任何人emplace_back() A的与私有构造成的容器构造A S',所以它不会真正解决什么,我还不如让构造公众这一点...

更新 :我要补充一点, A此举构造是价格昂贵不避不必调用它的唯一原因。 这可能是A不是在所有(也可复制)移动。 这不会与工作vector ,当然,(因为emplace_back()可能不得不重新分配向量),但它会用deque ,其中也有一个类似的emplace_back()方法,但没有重新分配任何东西。

Answer 1:

一个可能的解决方法(或杂牌)是使用一个辅助类来保存参数的构造函数私有A (我们称之为类EmplaceHelper )。 EmplaceHelper也应该有一个私人构造函数,它应该是在彼此的友谊A 现在,所有你需要的是一个在公共构造函数负责这种EmplaceHelper (通过常量-REF,可能),并利用该emplace_back(EmplaceHelper(...))

由于EmplaceHelper只能通过构造A ,你的公共构造函数仍然是有效的私有。

它甚至有可能来概括这个想法与模板EmplaceHelper(可能使用std::tuple来保存构造函数参数)。

编辑:其实,我似乎过于复杂这是一个评论如下从GManNickG给了我一个简单的想法:添加一个私有辅助类( private_ctor_t中的例子),这只是一个空的类,但因为它是私人,只有通过访问A 。 修改A的构造,包括这个私有类作为第一个(或最后一个)参数(并予以公布)。 其结果将是唯一A可以构造本身,如果它有一个私人的构造函数,但这种结构现在可以很容易地委派。

像这样:

#include <vector>
class A 
{ 
private:
    struct private_ctor_t {};

public:     
    A(private_ctor_t, int x) : A(x) // C++11 only, delegating constructor
    {}

    A(A&&) { /* somewhat expensive */ }

    static std::vector<A> make_As() 
    { 
        std::vector<A> result; 
        result.emplace_back(private_ctor_t{}, 3); 
        result.emplace_back(private_ctor_t{}, 4); 
        return result; 
    } 

private: 
    A(int) { /* private constructor */ }
}; 

如果委托构造函数是不可用,您可以从因素为每个版本的公共代码,或只是摆脱A(int)总共只有使用新版本。



Answer 2:

由C ++ 11个标准,所有标准容器应使用allocator::construct方法做就地建设。 因此,你可以简单地做std::allocator的朋友A

我想在技术上允许使用该功能委派实际施工调用别的东西。 就个人而言,我认为规范应该稍微更严格究竟执行哪些对象调用构造函数和能做什么和不能被委派。

如果发生,或者出于某种原因这种授权,你可以提供你自己的分配器转发所有呼叫std::allocator除了construct 。 我不建议后者,因为许多标准集装箱实现对处理特殊代码std::allocator ,使他们能够占用较少的空间。

刚刚意识到这样的朋友声明会允许任何人以emplace_back()A与私营构造成A的的容器构造,所以它不会真正解决什么,我还不如让构造公众在这一点上...

然后,你将不得不决定什么对你更重要的是:就地建设,或隐藏士兵。 通过这是非常自然的,现场施工意味着有人不是在你的代码是做建筑。 因此,有没有办法解决它:一些外部的代码必须被命名为朋友或构造函数必须是公开的。 总之,构造函数必须给谁就给谁委托建设公开访问。



Answer 3:

让我们简化一下。 下面无法编译,因为V有到A的私有的构造函数的访问权限。

struct V
{
    E(int i)
    {
        // ...
        auto a = A(i);
        // ...
    }
};

让我们回到你的代码,V仅仅是一个向量的简化,而V ::电子商务只是一个emplace_back做什么的简化。 矢量没有访问的私有构造函数,向量:: emplace_back需要调用它。



文章来源: Private constructor inhibits use of emplace[_back]() to avoid a move