C++ 의 생성자와 소멸자를 호출할 때, this 의 값은???

trymp의 이미지

C++ 로 코딩하는 초보입니다.

C++ 에서 생성자와 소멸자에서 this 를 이용해서 현재 object 의 포인터를 출력하는데
값이 다르게 나옵니다. 몇 byte 정도...

원래 this 가 같아야 하지 안나요?
다르게 나오는 경우도 있는지 궁금합니다.

고수님들의 조언 부탁드립니다.

HDNua의 이미지

답변은 아니고, 테스트하실 때 사용한 코드를 보여주실 수 있나요? 저도 궁금하네요.

저는 이렇게 생각했습니다.

익명 사용자의 이미지

다르면 안 될텐데요..

코드를 보여주실 수 있는지요? 저도 궁금하네요..ㅋㅋ

trymp의 이미지

인터넷에 있는 소스를 그대로 테스트 해 본 것입니다.

여기서 CTCP_Connection 에 대해 생성자와 소멸자 함수를 추가해서 this 를 출력해 보았습니다.
메모리 주소가 다르게 나오던군요..ㅠㅠ

#include"stdafx.h"
 
#include <ctime>
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <ctime>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
 
#include <boost/date_time/posix_time/posix_time.hpp>
 
using boost::asio::ip::tcp;
 
// 메세지를 만든다.
std::string make_daytime_string()
{
	using namespace std; // For time_t, time and ctime;
	time_t now = time(0);
	return ctime(&now);	// ctime_s 권장. 예제니까 그냥 쓰고 넘어가지만
}
 
class CTCP_Connection : public boost::enable_shared_from_this<CTCP_Connection>
{
private:
	tcp::socket m_Socket;
	std::string m_sMessage;
 
	CTCP_Connection(boost::asio::io_service& io_service) : m_Socket(io_service) // m_Socket 초기화
	{
	}
 
	// 안쓰니까 안전하게 봉인
	void handle_write(const boost::system::error_code& /*error*/, size_t /*bytes_transferred*/)
	{
	}
 
public:
	typedef boost::shared_ptr<CTCP_Connection> pointer;
 
	static pointer create(boost::asio::io_service& io_service)
	{
		return pointer(new CTCP_Connection(io_service));
	}
 
	tcp::socket& socket()
	{
		return m_Socket;
	}
 
	void start()
	{
		m_sMessage = make_daytime_string();
 
		// 예제에서는 boost::asio::async_write (boost::asio::error::eof 포함) 를 썼지만
		// async_write_some, async_send 를 써야할 것이다
		// error, bytes_tran 부분은 사용하지 않아도 된다
		boost::asio::async_write(m_Socket, boost::asio::buffer(m_sMessage),
			boost::bind(&CTCP_Connection::handle_write, shared_from_this(),
			boost::asio::placeholders::error,
			boost::asio::placeholders::bytes_transferred));
	}
};
 
class CTCP_Server
{
private:
	tcp::acceptor m_Acceptor;
 
	void start_accept()
	{
		CTCP_Connection::pointer new_connection =
			CTCP_Connection::create(m_Acceptor.get_io_service());
 
		m_Acceptor.async_accept(new_connection->socket(),
			boost::bind(&CTCP_Server::handle_accept, this, new_connection,
			boost::asio::placeholders::error));
	}
 
	void handle_accept(CTCP_Connection::pointer new_connection, const boost::system::error_code& error)
	{
		if (!error)
		{
			new_connection->start();
			start_accept();
		}
	}
 
public:
	CTCP_Server(boost::asio::io_service& io_service) : m_Acceptor(io_service, tcp::endpoint(tcp::v4(), 13))
	{
		start_accept();
	}
};
 
int _tmain(int argc, _TCHAR* argv[])
{
	try
	{
		boost::asio::io_service io_service;	// asio 라면 무조건 있어야 한다
 
		CTCP_Server server(io_service);
		io_service.run();
	}
	catch (std::exception& e)
	{
		std::cerr << e.what() << std::endl;
	}
 
	return 0;
}

gilgil의 이미지

multiple inheritance의 경우에는 this pointer가 달라질 수 있습니다만( http://www.gilgil.net/172 ) 올리신 코드에서 this를 출력하는 부분이 어디 있죠?

twinwings의 이미지

상속의 경우 포인터의 주소가 달라 질 수 있습니다.

이게 C++의 장점이자 단점/난점인데, 이게 컴파일러의 구현사항이라는 겁니다.

class Father;                  /* 객체의 크기가 100 Byte */
class Son : public Father;     /* 상속으로 인해 객체에 추가된 크기가 50 Byte */
 
Son    *s = new Son; /* 객체의 시작주소가 0번지 부터 시작한다고 가정 */
Father *f = (Father *)s;

이라고 할 때,

Father 클래스는 100byte

Son 클래스는 50byte 사용한다고 할게요. 객체의 실제 주소는 0번지부터 시작하고.

그러면 컴파일러마다 구현방법이 다르지만 그 구현중 하나는

Father *f의 값은 0, Son *s는 50이 됩니다. (다시 말하지만 컴파일러 구현에 종속적이니까 다르게 구현할 수도 있습니다.)

이 경우 Father 클래스 관계된 메소드를 호출할때는 컴파일할 때 Son의 This주소를 Father의 포인터로 캐스팅해서 호출하게 되지요.

(별개의 두개의 클래스가 존재하고, 메서드를 호출할때 자동으로 해당 객체로 캐스팅해서 호출해준다.. 뭐 이런 개념이죠)

그래서 C++에서는 캐스팅이 위험하다는 겁니다. C++에서의 포인터는 단순하게 객체의 "위치"를 가리키는게 아니라

"핸들"처럼 사용된다고 생각하시는게 낫습니다. 다른말로 하면 C처럼 저수준에서의 지지고 볶고 하시면 위험합니다.

gilgil의 이미지

multiple inheritance가 아닌 parent class가 하나일 경우에는 해당 객체에 대해서 부모 클래스 casting pointer와 자식 class casting pointer의 값은 다르지 않습니다.

twinwings의 이미지

지금 Effective C++이 없어서 인용할 수 없어 아쉬운데,

제 기억에 그 책에서 언급하기로 말 그대로 컴파일러 종속적이기 때문에

이론적으로는 얼마든지 다르게 나올 수 있다는 거죠.

따라서 이식성을 고려하거나 다른 눈에 보이지 않는 버그를 생성하지 않으려면

원천적으로 저수준의 조작은 하지 말아야 한다는게 제 글의 요지였습니다.

twinwings의 이미지

Effective C++ 3판 항목 27,

"사실 C++에서는 다중 상속이 사용되면 이런 현상이 항상 생기지만, 심지어 단일 상속인데도 이렇게 되는 경우가 있습니다."
(*여기서 현상은 업캐스팅 했을 때 포인터 값이 달라지는 현상을 지칭함)

"객체의 메모리 배치구조를 결정하는 방법과 객체의 주소를 계산하는 방법은 컴파일러마다 천차만별입니다. 그러니까, 어떤 플랫폼에서의 '메모리 배치를 다 꿰고 있어서' 캐스팅을 했을 때 문제가 없었을지라도 다른 플랫폼에서 그게 또 통하지는 않는다는 이야기죠."

"이를테면, 어떤 객체의 주소를 char* 포인터로 바꿔서 포인터 산술 연산을 적용하는 등의 코드는 거의 항상 미정의 동작을 낳을 수 있다는 이야기 입니다."

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.