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);
임시 StringBuffer 객체의 소멸자는 언제 호출됩니까? 그것은 :
- GetString을 호출하기 전에?
- GetString이 반환 된 후?
- 컴파일러 의존성?
C ++는 로컬 임시 변수에 대한 참조가있는 한 유효하다는 것을 보장한다는 것을 알고 있습니다. 멤버 변수에 대한 참조가있을 때 부모 개체에 적용됩니까?
감사.
답변
그런 종류의 임시에 대한 소멸자는 full-expression의 끝에서 호출됩니다. 그것은 다른 표현의 일부가 아닌 가장 외적인 표현입니다. 그것은 함수가 반환되고 값이 평가 된 후의 경우입니다. 따라서 모두 잘 작동합니다.
사실 식 템플릿이 작동하게 만드는 이유는 다음과 같습니다.
e = a + b * c / d
모든 일시적인 것이 표현 될 때까지 지속되기 때문에
x = y
완전히 평가됩니다. 12.2 Temporary objects
표준 에 아주 간결하게 설명되어 있습니다.
답변
litb의 대답은 정확합니다. 임시 객체 (rvalue라고도 함)의 수명은 표현식에 연결되어 있으며 임시 객체의 소멸자는 전체 표현식의 끝에서 호출되며 StringBuffer의 소멸자가 호출 될 때 m_buffer의 소멸자는 다음과 같습니다. 호출되었지만 참조이기 때문에 m_str의 소멸자는 아닙니다.
C ++ 0x는 rvalue 참조를 추가하고 의미 체계를 이동하기 때문에 약간만 변경됩니다. 본질적으로 rvalue 참조 매개 변수 (&&로 표시됨)를 사용하여 rvalue를 함수로 ‘이동’할 수 있으며 (복사하는 대신) rvalue의 수명은 표현식이 아닌 이동하는 객체에 바인딩 될 수 있습니다. 이에 대해 자세히 설명하는 MSVC 팀 의 정말 좋은 블로그 게시물이 있습니다.
rvalue의 이동에 대한 교육적 예제는 임시 문자열이며 생성자에서 할당을 보여 드리겠습니다. 문자열 멤버 변수를 포함하는 MyType 클래스가있는 경우 다음과 같이 생성자에서 rvalue로 초기화 할 수 있습니다.
class MyType{
const std::string m_name;
public:
MyType(const std::string&& name):m_name(name){};
}
임시 객체로이 클래스의 인스턴스를 선언 할 때 유용합니다.
void foo(){
MyType instance("hello");
}
일어나는 일은 우리가 임시 객체를 복사하고 파괴하는 것을 피하고 “hello”가 소유하는 클래스 인스턴스의 멤버 변수 안에 직접 배치된다는 것입니다. 객체가 ‘문자열’보다 무거운 경우 추가 복사 및 소멸자 호출이 중요 할 수 있습니다.
답변
GetString에 대한 호출이 반환 된 후.
답변
StringBuffer는 GetString의 범위에 있습니다. GetString의 범위가 끝날 때 (즉, 반환 될 때) 파괴되어야합니다. 또한 C ++가 참조가있는 한 변수가 존재한다는 것을 보장하지 않는다고 생각합니다.
다음을 컴파일해야합니다.
Object* obj = new Object;
Object& ref = &(*obj);
delete obj;
답변
나는 거의 똑같은 수업을 썼습니다.
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 ++에 대한 이전 Annotated Reference Manual이 범위의 끝에서 임시 파일을 정리해야한다고 지정했다고 생각하므로 일부 컴파일러는 그렇게했습니다. 2003 년 말에 필자는 Sun의 Forte C ++ 컴파일러에서 기본적으로 동작이 여전히 존재한다는 사실을 발견했기 때문에 StringBuffer가 작동하지 않았습니다. 그러나 현재의 컴파일러가 여전히 그렇게 망가 졌다면 놀랄 것입니다.