默认构造函数elision /赋值elision是否可能原则上? [英] Is default constructor elision / assignment elision possible in principle?

查看:93
本文介绍了默认构造函数elision /赋值elision是否可能原则上?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

。或者甚至由C ++ 11标准允许?

. or even allowed by the C++11 standard?

如果是这样,是否有任何编译器可以实现?

And if so, is there any compiler that actually does it?

这里是我的意思的一个例子:

Here is an example of what I mean:

template<class T> //T is a builtin type
class data 
{
public:
    constexpr
    data() noexcept :
        x_{0,0,0,0}
    {}

    constexpr
    data(const T& a, const T& b, const T& c, const T& d) noexcept :
        x_{a,b,c,d}
    {}

    data(const data&) noexcept = default;

    data& operator = (const data&) noexcept = default;

    constexpr const T&
    operator[] (std::size_t i) const noexcept {
        return x_[i];
    }

    T&
    operator[] (std::size_t i) noexcept {
        return x_[i];
    }

private:
    T x_[4];
};


template<class Ostream, class T>
Ostream& operator << (Ostream& os, const data<T>& d)
{
    return (os << d[0] <<' '<< d[1] <<' '<< d[2] <<' '<< d[3]);
}


template<class T>
inline constexpr
data<T>
get_data(const T& x, const T& y)
{
    return data<T>{x + y, x * y, x*x, y*y};
}


int main()
{
    double x, y;
    std::cin >> x >> y;

    auto d = data<double>{x, y, 2*x, 2*y};

    std::cout << d << std::endl;

    //THE QUESTION IS ABOUT THIS LINE
    d = get_data(x,y);  

    d[0] += d[2];
    d[1] += d[3];
    d[2] *= d[3];

    std::cout << d << std::endl;

    return 0;
}

关于标记行:

x + y,x * y,x * x,y * y直接写入d 0的存储器。
或者可以将get_data的返回类型直接构造在d的内存中?\\
我不能想到不允许这样的优化的原因。至少不适用于只有constexpr构造函数和默认复制和赋值运算符的类。

\\ b $ b g ++ 4.7.2删除了此示例中的所有复制构造函数;但是似乎总是执行赋值(即使对于默认赋值只有我从汇编中可以知道g ++发出)。
books

我的问题的动机是以下情况,其中这样的优化将大大简化和改进库设计。
假设您使用文字类编写性能关键的库例程。

Regarding the marked line:
Could the values x+y, x*y, x*x, y*y be written directly to the memory of d? Or could the return type of get_data be directly constructed in the memory of d?
I can't think of a reason to not allow such an optimization. At least not for a class that has only constexpr constructors and default copy and assignment operators.

g++ 4.7.2 elides all copy constructors in this example; it seems however that assignment is always performed (even for default assignment only - as far as I can tell from the assembly that g++ emits).

The motivation for my question is the following situation in which such an optimization would greatly simplify and improve library design. Suppose you write performance-critical library routines using a literal class. Objects of that class will hold enough data (say 20 doubles) that copies have to be kept to a minimum.

class Literal{ constexpr Literal(...): {...} {} ...};

//nice: allows RVO and is guaranteed to not have any side effects
constexpr Literal get_random_literal(RandomEngine&) {return Literal{....}; }

//not favorable in my opinion: possible non-obvious side-effects, code duplication
//would be superfluous if said optimization were performed
void set_literal_random(RandomEngine&, Literal&) {...}

设计如果我可以做没有第二个功能。但有时我只需要修改一个长寿命的Literal对象,并确保我不创建一个新的,并将其分配给我要修改的一个。修改本身很便宜,副本不是 - 这是我的实验表明。

It would make for a much cleaner (functional programming style) design if I could do without the second function. But sometimes I just need to modify a long-lived Literal object and have to make sure that I don't create a new one and copy-assign it to the one I want to modify. The modification itself is cheap, the copies aren't - that's what my experiments indicate.

编辑:

让我们假设优化只有允许具有noexcept constexpr构造函数和noexcept默认operator =的类。


Let's suppose the optimization shall only be allowed for a class with noexcept constexpr constructors and noexcept default operator=.

推荐答案

允许默认复制/只对一般的假设规则。这是编译器可以做的,如果它可以确定它将对行为没有可观察到的影响。

Elision of default copy/move assignment operators is allowed based on the general as-if rule only. That is the compiler can do it if it can ascertain that it will have no observable effect on behaviour.

在实践中,as-if规则以一般方式使用中间表示和装配级别的优化。如果编译器可以内联默认构造函数和赋值,它可以优化它们。它不会使用复制构造函数的代码,但对于它们的默认实现,它应该以相同的代码结束。

In practice the as-if rule is used in general fashion to allow optimizations at intermediate representation and assembly levels. If the compiler can inline the default constructor and assignment, it can optimize them. It won't ever use the code of the copy constructor for it, but for their default implementations it should end up with the same code.

编辑:是代码示例。复制/移动构造函数基于对编译器的显式权限而省略,因此即使它们具有可观察的效果(打印COPY),它们也会被省略。分配只能根据as-if规则省略,但它们具有可观察到的效果(打印ASSIGN),因此编译器不允许触摸它们。

I answered before there was the code sample. Copy/move constructors are elided based on explicit permission to the compiler to do so, therefore they are elided even if they have observable effect (printing "COPY"). Assignments can only be elided based on as-if rule, but they have observable effect (printing "ASSIGN"), so the compiler is not allowed to touch them.

这篇关于默认构造函数elision /赋值elision是否可能原则上?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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