c++17 temporary materialization

3 篇文章 0 订阅
1 篇文章 0 订阅

c++17 temporary materialization

c++17要求【prvalue(纯右值)/临时值】不能被轻易物化,除非有必要

1. value categories

左值(lvalue)和右值(rvalue)

C++11之前,左值和右值定义很清晰(传统C定义),左值代表一个位置,具有程序可访问的内存地址,右值代表内容;另一种表述是根据赋值操作的角色进行描述,左值在赋值操作的左边(left-hand side),右值在赋值操作的右边(right-hand side)。

两属性三类别

C++11之后引入了右值引用和移动语义新特性,导致左值和右值并不容易解释了,因此出现了新的值类别,如下。

  • 两属性
    任何一个值(表达式)都有两个属性:
    具有身份(has identity):具有内存地址,程序可以访问该地址;-- 广义左值(glvalue)
    可被移动(can be moved from): 移动之后,undefined but valid(state); – 右值(rvalue)
  • 三类别
    具有身份+不可移动:左值(lvalue);
    具有身份+可以移动:过期的值(xvalue);
    没有身份+可以移动:纯右值(prvalue);
expression
glvalue
rvalue
lvalue
xvalue
prvalue

2. 针对prvalue的处理,是否一定要temporary materialization?

纯右值是一个不占据内存的值,可以用来初始化对象,在C++17之前纯右值通常表示一个临时对象(占据内存,隐式prvalue-to-xvalue转换,因此类型必须具有拷贝构造函数,即使编译器优化后不再调用拷贝构造函数,编译器依然会检查拷贝语义);C++17 强制要求纯右值prvalue只是初始化语义,意思是prvalue只能帮助其它对象初始化,自己是不能轻易物化(materialization)的,除非有必要。

// temporary_materialization.cpp
#include <iostream>

class Test
{
public:
    Test() : m(1)
    {
        std::cout << "ctor" << std::endl;
    }
    Test(const Test&)
    {
        std::cout << "copy ctor" << std::endl;
    }
    ~Test()
    {
        std::cout << "dtor" << std::endl;
    }

private:
    int m;
};

Test Func(Test test)
{
    std::cout << "Func called" << std::endl;
    return Test();
}

int main()
{
    auto t = Func(Test());
    return 0;
}

g++ temporary_materialization.cpp -fno-elide-constructors -std=c++11
输出:
ctor
copy ctor
Func called
ctor
copy ctor
dtor
copy ctor
dtor
dtor
dtor
dtor

-fno-elide-constructors编译选项是告诉编译器不要进行优化,防止编译器优化掩盖我们想表达的意思。
可以看出c++11,Test()最终代表一个临时值,而不是一个纯右值(发生了prvalue-to-xvalue),导致出现了大量拷贝构造函数。

g++ temporary_materialization.cpp -fno-elide-constructors -std=c++17
输出:
ctor
Func called
ctor
dtor
dtor

可以看出c++17对待Test()根据上下文完全把其当作了prvalue,只是用其初始化对象而已,因此不存在拷贝构造函数的调用。

进一步思考

如果去除编译选项 -fno-elide-constructors,c++11启用优化(rvo),也不会出现拷贝构造函数的调用,如下:

g++ temporary_materialization.cpp -std=c++11
输出:
ctor
Func called
ctor
dtor
dtor

此时是否可以把拷贝构造函数删除?
答案是不可以。

// temporary_materialization.cpp
#include <iostream>

class Test
{
public:
    Test() : m(1)
    {
        std::cout << "ctor" << std::endl;
    }
    Test(const Test&) = delete; //change
    ~Test()
    {
        std::cout << "dtor" << std::endl;
    }

private:
    int m;
};

Test Func(Test test)
{
    std::cout << "Func called" << std::endl;
    return Test();
}

int main()
{
    auto t = Func(Test());
    return 0;
}

c++11编译无法通过,但C++17可以通过。

g++ temporary_materialization.cpp -std=c++11
输出:
temporary_materialization.cpp:30:12: error: call to deleted constructor of ‘Test’
return Test();
^~~~~~
temporary_materialization.cpp:16:5: note: ‘Test’ has been explicitly marked deleted here
Test(const Test&) = delete;
^
temporary_materialization.cpp:35:19: error: call to deleted constructor of ‘Test’
auto t = Func(Test());
^~~~~~
temporary_materialization.cpp:16:5: note: ‘Test’ has been explicitly marked deleted here
Test(const Test&) = delete;
^
temporary_materialization.cpp:27:16: note: passing argument to parameter ‘test’ here
Test Func(Test test)
^
2 errors generated.

g++ temporary_materialization.cpp -std=c++17
输出:
ctor
Func called
ctor
dtor
dtor

这也印证了前文的描述:

在C++17之前纯右值通常表示一个临时对象(占据内存,隐式prvalue-to-xvalue转换,因此类型必须具有拷贝构造函数,即使编译器优化后不再调用拷贝构造函数,编译器依然会检查拷贝语义);C++17 强制要求纯右值prvalue只是初始化语义,意思是prvalue只能帮助其它对象初始化,自己是不能轻易物化的,除非有必要。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Inside the C++ Object Model focuses on the underlying mechanisms that support object-oriented programming within C++: constructor semantics, temporary generation, support for encapsulation, inheritance, and "the virtuals"--virtual functions and virtual inheritance. This book shows how your understanding the underlying implementation models can help you code more efficiently and with greater confidence. Lippman dispells the misinformation and myths about the overhead and complexity associated with C++, while pointing out areas in which costs and trade offs, sometimes hidden, do exist. He then explains how the various implementation models arose, points out areas in which they are likely to evolve, and why they are what they are. He covers the semantic implications of the C++ object model and how that model affects your programs. Highlights *Explores the program behavior implicit in the C++ Object Model's support of object-oriented programming. *Explains the basic implementation of the object-oriented features and the trade offs implicit in those features. *Examines the impact on performance in terms of program transformation.* Provides abundant program examples, diagrams, and performance measurements to relate object-oriented concepts to the underlying object model. If you are a C++ programmer who desires a fuller understanding of what is going on "under the hood," then Inside the C++ Object Model is for you! Get a value-added service! Try out all the examples from this book at www.codesaw.com. CodeSaw is a free online learning tool that allows you to experiment with live code from your book right in your browser.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值