私有构造函数禁止使用emplace [_back]()来避免移动 [英] Private constructor inhibits use of emplace[_back]() to avoid a move

查看:312
本文介绍了私有构造函数禁止使用emplace [_back]()来避免移动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下代码:

  #include< vector& 

class A
{
public:
A(A&&); //有点贵

static std :: vector< A> make_As()
{
std :: vector< A>结果;
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&&); //有点贵

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

private:
A(int); // private constructor
};不幸的是,使用 emplace_back(),可以将


$ b实际的构造函数调用是由标准库中的某个东西完成的,它没有足够的特权能够调用 A 的私有构造函数。



我意识到可能没有什么可以做到的,但是我觉得,因为 emplace_back()的调用发生在 A ,他们应该能够调用私有构造函数。



解决方法?



我唯一能想到的是在 A 中添加一个friend声明需要 A 的朋友(即实际尝试调用构造函数的类)的精确类是实现特定的(例如,对于GCC,它的 __gnu_cxx :: new_allocator< A> )。 EDIT :刚刚意识到这样的朋友声明将允许任何人 emplace_back() A 的构造与私人构造函数到一个容器 A 的,所以它不会真正解决任何东西,我也可以使

UPDATE :我应该添加 A 的移动构造函数是昂贵的并不是避免不得不调用它的唯一原因。可能是 A 根本不可移动(也不可复制)。这不会使用向量,当然,(因为 emplace_back()可能必须重新分配向量,它将与 deque ,它也有类似的 emplace_back()方法,但不必重新分配任何东西。 p>

解决方案

一个可能的解决方法是使用一个帮助类来保存 A (我们称之为 EmplaceHelper )。 EmplaceHelper也应该有一个私人ctor,它应该与 A 相互友谊。现在你需要的是一个公共的代码在A中,使用这个 EmplaceHelper (通过const-ref,可能),并使用 emplace_back ...))



由于 EmplaceHelper 只能由 A



甚至可能使用模板化的EmplaceHelper来概括这个想法(可能使用 std :: tuple 保存ctor参数)。



编辑:实际上,似乎我过于复杂这下面GManNickG给我一个更简单的想法:EmplaceHelper可能只是一个空类(仍然与私人ctor,与A如上友谊),但它不需要存储所有ctor params,只是修改您的私人ctor包括EmplaceHelper作为第一个(或最后一个)参数(并使其公开)。效果将与上面相同,但没有EmplaceHelper中的复杂逻辑。



像这样:

  class A 
{
private:
struct private_key {};

public:
A(int x,const private_key&):
A(x)// C ++ 11,委托构造函数
{}

A(A&& amp;); //有点贵

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

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

如果委派的构造函数不可用,您可以分解每个版本的公共代码,除去 A(int),并且只能使用新版本,可能使用默认的第二个参数。


Consider the following code:

#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
};

Since A's move constructor is somewhat expensive (for whatever reason), I'd like to avoid calling it and use emplace_back() instead:

#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
};

Unfortunately, with emplace_back(), the actual constructor call is done by something in the standard library, which is not privileged enough to be able to call A's private constructor.

I realize that there's probably little that can be done about this, but nonetheless I feel that since the calls to emplace_back() occur within a member of A, they ought to be able to call the private constructor.

Are there any workarounds for this?

The only thing I can think of is to add a friend-declaration to A, but the precise class that needs to be A's friend (that is, the class that actually tries to invoke the constructor) is implementation-specific (for example, for GCC it's __gnu_cxx::new_allocator<A>). EDIT: just realized that such a friend declaration will allow anyone to emplace_back() A's constructed with the private constructor into a container of A's, so it wouldn't really solve anything, I might as well make the constructor public at that point...

UPDATE: I should add that A's move constructor being expensive is not the only reason to avoid having to call it. It may be that A is not movable at all (nor copyable). That would not work with vector, of course, (because emplace_back() may have to reallocate the vector), but it would with deque, which also has a similar emplace_back() method but does not have to reallocate anything.

解决方案

One possible workaround (or kludge) would be to use a helper class to hold the parameters to the private ctor of A (let's call this class EmplaceHelper). EmplaceHelper should also have a private ctor, and it should be in mutual friendship with A. Now all you need is a public ctor in A that takes this EmplaceHelper (via const-ref, probably), and use that with emplace_back(EmplaceHelper(...)).

Since EmplaceHelper can only be constructed by A, your public ctor is still effectively private.

It might even be possible to generalize this idea with a templated EmplaceHelper (possibly using std::tuple to hold the ctor parameters).

Edit: actually, it seems I overcomplicated this as a comment below from GManNickG gave me a simpler idea: EmplaceHelper could be just an empty class (still with private ctor, in friendship with A as above) but it needn't store all ctor params, just modify your private ctor to include EmplaceHelper as the first (or last) parameter (and make it public). The effect would be the same as above, but without the complicated logic in EmplaceHelper.

Like this:

class A 
{ 
private:
    struct private_key {};

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

    A(A&&);  // somewhat expensive 

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

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

If delegated constructors are not available, you can either factor out the common code for each version, or just get rid of A(int) altogether and only use the new version, possibly with a defaulted second parameter.

这篇关于私有构造函数禁止使用emplace [_back]()来避免移动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆