代码之家  ›  专栏  ›  技术社区  ›  Mark Ransom

C++中临时的保证生命周期?[副本]

c++
  •  109
  • Mark Ransom  · 技术社区  · 17 年前

    C++是否为在函数调用中创建但未用作参数的临时变量的生命周期提供保证?下面是一个示例类:

    class StringBuffer
    {
    public:
        StringBuffer(std::string & str) : m_str(str)
        {
            m_buffer.push_back(0);
        }
        ~StringBuffer()
        {
            m_str = &m_buffer[0];
        }
        char * Size(int maxlength)
        {
            m_buffer.resize(maxlength + 1, 0);
            return &m_buffer[0];
        }
    private:
        std::string & m_str;
        std::vector<char> m_buffer;
    };
    

    以下是您将如何使用它:

    // this is from a crusty old API that can't be changed
    void GetString(char * str, int maxlength);
    
    std::string mystring;
    GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);
    

    • 在调用GetString之前?

    6 回复  |  直到 17 年前
        1
  •  114
  •   Johannes Schaub - litb    17 年前

    这种临时对象的析构函数在完整表达式的末尾被调用。这是最外在的表达,不是任何其他表达的一部分。这是在函数返回并计算值之后。所以,一切都会好起来的。

    e = a + b * c / d
    

    因为每一个暂时的都会持续到表达

    x = y
    

    已完全评估。它在 12.2 Temporary objects 在标准中。

        2
  •  18
  •   Marco A.    11 年前

    请注意,C++0x只改变了一点点,因为它添加了右值引用和移动语义。本质上,通过使用右值引用参数(用&amp;表示),我可以将右值“移动”到函数中(而不是复制它),并且右值的生存期可以绑定到它移动到的对象,而不是表达式。有一个非常好的 blog post from the MSVC team on that walks through this in great detail 我鼓励人们阅读它。

    移动右值的教学示例是临时字符串,我将在构造函数中显示赋值。如果我有一个包含字符串成员变量的MyType类,它可以在构造函数中用右值初始化,如下所示:

    class MyType{
       const std::string m_name;
    public:
       MyType(const std::string&& name):m_name(name){};
    }
    

    这很好,因为当我用临时对象声明这个类的实例时:

    void foo(){
        MyType instance("hello");
    }
    

    实际情况是,我们避免复制和销毁临时对象,并且“hello”直接放置在所属类实例的成员变量中。如果对象的权重比“字符串”重,那么额外的复制和析构函数调用可能会很重要。

        3
  •  4
  •   David Segonds    17 年前

    在GetString调用返回后。

        4
  •  4
  •   Daniel Earwicker    13 年前

    我写了几乎完全相同的类:

    template <class C>
    class _StringBuffer
    {
        typename std::basic_string<C> &m_str;
        typename std::vector<C> m_buffer;
    
    public:
        _StringBuffer(std::basic_string<C> &str, size_t nSize)
            : m_str(str), m_buffer(nSize + 1) { get()[nSize] = (C)0; }
    
        ~_StringBuffer()
            { commit(); }
    
        C *get()
            { return &(m_buffer[0]); }
    
        operator C *()
            { return get(); }
    
        void commit()
        {
            if (m_buffer.size() != 0)
            {
                size_t l = std::char_traits<C>::length(get());
                m_str.assign(get(), l);    
                m_buffer.resize(0);
            }
        }
    
        void abort()
            { m_buffer.resize(0); }
    };
    
    template <class C>
    inline _StringBuffer<C> StringBuffer(typename std::basic_string<C> &str, size_t nSize)
        { return _StringBuffer<C>(str, nSize); }
    

    在标准之前,每个编译器都有不同的做法。我相信旧的《C++注释参考手册》规定,临时文件应在作用域结束时清理,所以一些编译器这样做了。直到2003年,我才发现Sun的Forte C++编译器默认情况下仍然存在这种行为,因此StringBuffer不起作用。但如果任何当前的编译器仍然如此损坏,我会感到惊讶。

        5
  •  3
  •   BigSandwich    17 年前

    StringBuffer在GetString的作用域内。它应该在GetString作用域结束时(即返回时)被销毁。此外,我不相信C++会保证变量只要有引用就存在。

    应编制以下内容:

    Object* obj = new Object;
    Object& ref = &(*obj);
    delete obj;