Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/153.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 有没有办法延长C+中临时对象的生存期+;?_C++_C++11_Scope_Temporary_Scopeguard - Fatal编程技术网

C++ 有没有办法延长C+中临时对象的生存期+;?

C++ 有没有办法延长C+中临时对象的生存期+;?,c++,c++11,scope,temporary,scopeguard,C++,C++11,Scope,Temporary,Scopeguard,我编写了一个范围保护程序,在范围退出时重置一个值: template <class T> struct ResetGuard { T old_value; T& obj_to_reset; ResetGuard(T& obj_to_reset, const T& new_value) : old_value(obj_to_reset), obj_to_reset(obj_to_reset) {

我编写了一个范围保护程序,在范围退出时重置一个值:

template <class T>
struct ResetGuard
{
    T old_value;
    T& obj_to_reset;
    ResetGuard(T& obj_to_reset, const T& new_value) :
        old_value(obj_to_reset),
        obj_to_reset(obj_to_reset)
    {
        obj_to_reset = new_value;
    }

    ~ResetGuard() { obj_to_reset = old_value; }
};
模板
结构重置保护
{
T旧值;
T&obj_至_重置;
重置保护(T&obj\U至\U重置、常数T和新值):
旧_值(obj_至_重置),
obj_至_重置(obj_至_重置)
{
obj_至_重置=新的_值;
}
~ResetGuard(){obj_to_reset=old_value;}
};
当从函数返回此范围保护时,如果未保存,是否有任何方法防止立即销毁范围保护

例如:

int GLOBAL_VALUE = 0;
ResetGuard<int> temporarily_set_global_value(int new_val) {
    return { GLOBAL_VALUE, new_val }; //updates the global variable
}
void foo() {
    //Ideally, someone calling this function
    //Wouldn't have to save the returned value to a local variable
    temporarily_set_global_value(15);
    std::cout << "GLOBAL_VALUE is " << GLOBAL_VALUE << std::endl;
}
int全局值=0;
ResetGuard临时设置全局值(int new值){
返回{GLOBAL_VALUE,new_val};//更新全局变量
}
void foo(){
//理想情况下,调用此函数的人
//不必将返回值保存到局部变量
临时设置全局值(15);
标准::cout

是否有任何方法来延长C++中的临时对象的生存期?

只有一种方法,将其分配给一个变量(可能是引用)。如果您不想给库的用户带来负担,可以将细节隐藏在宏后面。虽然宏的使用确实越来越少,但这是您只能使用宏来完成的。例如,您可以通过少量的GCC扩展来完成:

#define CONCAT(a, b) a##b
#define SCOPED_GLOBAL_VALUE(x) \
  auto&& CONCAT(_unused, __COUNTER__) __attribute__((unused)) = temporarily_set_global_value(x)
因此,现在当用户编写:

SCOPED_GLOBAL_VALUE(15);
他们可以免费获得具有您想要的表现力的变量

当然,有一个警告。因为我们使用预处理器生成变量名,所以我们不能在内联函数中使用这个宏。如果我们这样做,我们将违反一个定义规则。所以这是一个需要考虑的事情。


P>个人,我不会强调这一点。这是一个常见的习惯用法,需要命名的RAII对象(思考<代码> CordyGueGue/Cuff>),所以只要呈现一个正确命名的函数,对于任何精明的C++程序员来说都是直接的。

< P>对不起我以前的回答,我在想什么?我应该正确地阅读问题。 因此,当然,
foo()
必须返回您的
ResetGuard
对象以延长其生命周期,这是一件好事,而不是坏事

首先,这几乎不是打电话的人的负担。毕竟,他/她所要做的就是:

auto rg = foo ();
作为
foo()
的潜在调用者,我绝对不会有任何问题,而且@melpomene在上述评论中的极好的建议(
[[nodiscard]]
)可以用来确保调用者不会忘记这样做

为什么强制调用方这样做是一件好事(除了您在这件事上没有选择之外)?好吧,它让调用方有机会管理scopeguard的生命周期,这可能很有用(很快将提供实时演示)

至于这里的其他答案,我绝对不会在宏中隐藏所有这些内容,因为这会对
foo()
的潜在调用方隐藏一条重要信息。相反,我会使用
[[nodiscard]]]
提醒他们的责任,并将其保留

[编辑]

我现在在Wandbox花了一点时间润色代码,添加了全套推荐的构造函数/赋值运算符,并演示了
[[nodiscard]]
的使用,这对我来说是一天中的发现

首先,修改后的类,按照(我相信)知道的人推荐的方式完成。我特别明白定义一个适当的移动构造函数的重要性(只要想想如果不这样做可能会遇到的细微错误)。从JVApen中删掉一些东西(
=delete
),在我看来是明智的,TU JV

#include <iostream>
#include <assert.h>

#define INCLUDE_COPY_MOVE_SWAP_STUFF

template <class T> class [[nodiscard]] ResetGuard
{
public:
    ResetGuard (T& obj_to_reset, const T& new_value) : old_value (obj_to_reset), obj_to_reset (obj_to_reset)
    {
        obj_to_reset = new_value;
    }

#ifdef INCLUDE_COPY_MOVE_SWAP_STUFF
   ResetGuard (const ResetGuard& copy_from) = delete;
   ResetGuard &operator= (const ResetGuard& copy_assign_from) = delete;
   ResetGuard &operator= (ResetGuard&& move_assign_from) = delete;  

    ResetGuard (ResetGuard&& move_from) : old_value (move_from.old_value), obj_to_reset (move_from.obj_to_reset)
    {
        assert (!move_from.defunct);
        move_from.defunct = true;
    }
#endif

    ~ResetGuard()
    {
        if (!defunct)
            obj_to_reset = old_value;
    }

private:
    T old_value;
    T& obj_to_reset;
    bool defunct = false;
};
编译器输出:

prog.cc: In function 'void bad_foo()':
prog.cc:47:38: warning: ignoring returned value of type 'ResetGuard<int>', declared with attribute nodiscard [-Wunused-result]
     temporarily_set_global_value (15);
                                      ^
prog.cc:40:17: note: in call to 'ResetGuard<int> temporarily_set_global_value(int)', declared here
 ResetGuard<int> temporarily_set_global_value (int new_val)
                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:6:40: note: 'ResetGuard<int>' declared here
 template <class T> class [[nodiscard]] ResetGuard
                                        ^~~~~~~~~~
如果你做了所有你应该做的事情(我希望我做了!),那么一切都很好,而且由于RVO和保证的拷贝省略,一切都很好,效率很高,所以也不必担心


在回答你的问题之前,我想提供C++中解决这个问题的正确方法。
template <class T>
struct [[nodiscard]] ResetGuard
{
    T old_value;
    T& obj_to_reset;
    bool enabled{true};

    ResetGuard(T& obj_to_reset, const T& new_value) :
       old_value(obj_to_reset),
       obj_to_reset(obj_to_reset)
    {
       obj_to_reset = new_value;
    }

    ResetGuard(ResetGuard &&rhs)
       : old_value(rhs.old_value)
       , obj_to_reset(obj_to_reset)
    {
        rhs.enabled = false;
    }
    ~ResetGuard()
    {
        if (enabled)
            obj_to_reset = old_value;
    }
    ResetGuard(const ResetGuard &) = delete;
    ResetGuard &operator=(const ResetGuard &) = delete;
    ResetGuard &operator=(ResetGuard &&) = delete;  
};

void foo() {
    auto guard = temporarily_set_global_value(15);
    std::cout << "GLOBAL_VALUE is " << GLOBAL_VALUE << std::endl;
}

但是,我不清楚您总共有多少个实例。但是,如果您将解决方案与move构造函数一起使用,这不再是一个问题。此外,当您使用编译器优化时,此函数在头中实现时可以内联。这可能会消除所有副本。

如何实现move构造函数卡车司机说得对吗?(附言:别忘了第五条规则)(这听起来很可怕。)为什么要避免使用局部变量?这是这类事情的常用习惯用法。这是一个最小的工作示例。我之所以要避免使用局部变量,是因为我想让代码尽可能防弹:我不想因为有人忘了将范围保护保存到局部变量而导致某些事情失败。为什么不直接标记它是?听起来像…嗯?为什么不在内联函数中?作用域的规则与非内联函数的规则完全相同,不是吗?@Aconcagua-如果将包含内联函数的头包含在两个不同的转换单元中,则在处理每个TU后,变量可能会有不同的名称。这将违反requirement.啊,我明白了-
静态内联
应该可以解决这个问题-是不是?或者可能是
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu我知道计算的是什么,但我认为这是所有包含内容完成后的当前TU。我可能是错的。test.c:
1:#include 2:void f(){log(“something”)}
如果现在在包含内容后解决了
\uu LINE
,日志系统如何有意义地使用它(打印
行:101
而不是
行:1
)?我认为不会
GLOBAL_VALUE in bad_foo () is 0
GLOBAL_VALUE in good_foo () is 15
GLOBAL_VALUE after good_foo () returns is 0
GLOBAL_VALUE in better_foo () is 15
GLOBAL_VALUE after better_foo () returns is 15
GLOBAL_VALUE after ResetGuard moved is 15
GLOBAL_VALUE after ResetGuard moved to goes out of scope is 0
GLOBAL_VALUE after ResetGuard moved from goes out of scope is 42 
template <class T>
struct [[nodiscard]] ResetGuard
{
    T old_value;
    T& obj_to_reset;
    bool enabled{true};

    ResetGuard(T& obj_to_reset, const T& new_value) :
       old_value(obj_to_reset),
       obj_to_reset(obj_to_reset)
    {
       obj_to_reset = new_value;
    }

    ResetGuard(ResetGuard &&rhs)
       : old_value(rhs.old_value)
       , obj_to_reset(obj_to_reset)
    {
        rhs.enabled = false;
    }
    ~ResetGuard()
    {
        if (enabled)
            obj_to_reset = old_value;
    }
    ResetGuard(const ResetGuard &) = delete;
    ResetGuard &operator=(const ResetGuard &) = delete;
    ResetGuard &operator=(ResetGuard &&) = delete;  
};

void foo() {
    auto guard = temporarily_set_global_value(15);
    std::cout << "GLOBAL_VALUE is " << GLOBAL_VALUE << std::endl;
}
const auto &guard = temporarily_set_global_value(15);