避免需要#define与表达式模板 [英] Avoiding need for #define with expression templates

查看:180
本文介绍了避免需要#define与表达式模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用以下代码,hello2不会显示为在执行第4行之前在第3行模具上创建的临时字符串。使用#define作为行1避免了这个问题,但有没有一种方法,以避免使用#define? (C ++ 11代码没问题)

  #include< iostream> 
#include< string>

class C
{
public:
C(const std :: string& p_s):s(p_s){}
const std ::字符串& s;
};

int main()
{
#define x1 C(std :: string(hello1))//行1
std :: cout< < x1.s<< std :: endl; // Line 2

const C& x2 = C(std :: string(hello2)); // Line 3
std :: cout<< x2.s<< std :: endl; // Line 4
}

说明: >

注意,我相信Boost uBLAS存储引用,这就是为什么我不想存储副本。

解决方案

如果你建议我按价值存储,请解释为什么Boost uBLAS错误和按值存储不会影响性能。通过引用存储的表达式模板通常这样做是为了性能,但是注意它们只用作临时表。



取自文档的Boost.Proto(可用于创建表达式模板):


注意精明的读者会注意到,悬挂引用一个临时int。在Proto的各种高性能应用程序中,通常在任何临时对象超出范围之前构建和计算表达式树,所以这种悬挂的引用情况通常不会出现,但它肯定是需要注意的。 Proto提供了用于深度复制表达式树的实用程序,因此它们可以作为值类型传递,而不用担心引用的悬挂。


示例这意味着你应该做:

  std :: cout< C(std :: string(hello2))。<< std :: endl; 

这样, C std :: string 临时。



因为你提到C ++ 11,所以你可以使用 s 在未来我期望表达式树按值存储,使用移动语义避免昂贵的复制和包装器,如std :: reference_wrapper仍然提供通过引用存储的选项。



可能的C ++ 11版本的代码:

  class C 
{
public:
explicit
C(std :: string const& s_):s {s_} {}

explicit
C(std :: string& s_):s {std :: move(s_)} {}

std :: string const&
get()const& // notice lvalue * this
{return s; }

std :: string
get()&& // notice rvalue * this
{return std :: move(s); }

private:
std :: string s; // not const to enable moving
};

这意味着像 C(hello)。get )只会分配内存一次,但仍然可以使用

  std :: string clvalue你好); 
auto c = C(clvalue);
std :: cout<< c.get()<< '\\\
'; // no problem here


With the following code, "hello2" is not displayed as the temporary string created on Line 3 dies before Line 4 is executed. Using a #define as on Line 1 avoids this issue, but is there a way to avoid this issue without using #define? (C++11 code is okay)

#include <iostream>
#include <string>

class C
{
public:
  C(const std::string& p_s) : s(p_s) {}
  const std::string& s;
};

int main()
{
  #define x1 C(std::string("hello1")) // Line 1
  std::cout << x1.s << std::endl; // Line 2

  const C& x2 = C(std::string("hello2")); // Line 3
  std::cout << x2.s << std::endl; // Line 4
}

Clarification:

Note that I believe Boost uBLAS stores references, this is why I don't want to store a copy. If you suggest that I store by value, please explain why Boost uBLAS is wrong and storing by value will not affect performance.

解决方案

Expression templates that do store by reference typically do so for performance, but with the caveat they only be used as temporaries

Taken from the documentation of Boost.Proto (which can be used to create expression templates):

Note An astute reader will notice that the object y defined above will be left holding a dangling reference to a temporary int. In the sorts of high-performance applications Proto addresses, it is typical to build and evaluate an expression tree before any temporary objects go out of scope, so this dangling reference situation often doesn't arise, but it is certainly something to be aware of. Proto provides utilities for deep-copying expression trees so they can be passed around as value types without concern for dangling references.

In your initial example this means that you should do:

std::cout << C(std::string("hello2")).s << std::endl;

That way the C temporary never outlives the std::string temporary. Alternatively you could make s a non reference member as others pointed out.

Since you mention C++11, in the future I expect expression trees to store by value, using move semantics to avoid expensive copying and wrappers like std::reference_wrapper to still give the option of storing by reference. This would play nicely with auto.

A possible C++11 version of your code:

class C
{
public:
    explicit
    C(std::string const& s_): s { s_ } {}

    explicit
    C(std::string&& s_): s { std::move(s_) } {}

    std::string const&
    get() const& // notice lvalue *this
    { return s; }

    std::string
    get() && // notice rvalue *this
    { return std::move(s); }

private:
    std::string s; // not const to enable moving
};

This would mean that code like C("hello").get() would only allocate memory once, but still play nice with

std::string clvalue("hello");
auto c = C(clvalue);
std::cout << c.get() << '\n'; // no problem here

这篇关于避免需要#define与表达式模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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