2중 vector 를 포인터로 액세스할때 에러
글쓴이: jinserk / 작성시간: 화, 2009/11/03 - 8:46오후
아래 질문의 연장입니다. :( 이것때문에 계속 고생이네요.
class A { typedef std::vector<T> T_vec; typedef std::vector<T_vec> T_mat; T_mat x; B b; A : b(&x) () {}; }; class B { typedef std::vector<T> T_vec; typedef std::vector<T_vec> T_mat; B(T_mat* px) { px->resize(10) };
2차원 matrix 표현을 위해 vector 를 위와 같이 선언해줬는데,
class B 에서 px->resize() 부르는 부분에서 access violation 이 발생합니다.
아무리 생각해도 잘모르겠네요.. 도움 부탁드립니다.
Forums:
흠...
제가 알기로는 member 변수들의 생성순서는 정해져 있지 않은 것으로 아는데...
그래서 그런게 아닐까 싶다는...
class B에서 사용된
class B에서 사용된 T가 명확하지 않은데요.
템플릿을 만드시는 건가요?
아.. 물론 T 는
T 는 제가 만든 complex 데이터 형 template 클래스가 들어갑니다.
class A, B 가 템플릿은 아니지만
T = complex<double>
이라고 보시면 될듯..Leo.
흠.. 의심스러운 부분이 있네요.
조금더 테스트를 해보았습니다.
원래 class A 역시 vector 에 들어가는 데이터 구조라.. 전체적으로 보면 아래와 같은 구조입니다.
이때 a_vec 에 들어가는 &buffer 를 찍어보니까, 모두 같은 주소를 갖고 있네요.
A a 를 만든다음 push_back 하니까 같은 주소로 매핑되나봅니다.
그래서 a_vec.resize(3) 과 같은 형식으로 바꾸고 class A 의 constructor 를
void initialize(int x) 와 같은 멤버 함수로 바꾼다음 a_vec[i].initialize() 를
부르는 식으로 바꿔봤는데, 이런 경우는 &buffer 가 모두 다른 값을 가지게 됩니다만,
역시나 resize 를 하면 segmentation fault 를 내버립니다.
class 의 멤버변수로 2중 vector 를 쓰면 문제가 되는걸까요? 난감하네요.
Leo.
C++이 객체를
C++이 객체를 생성하는 순서와
특히 객체 생성시 초기화 순서(콜론 초기화, 생성자 블럭 외 초기화, 생성자 블럭 내 초기화)를
찾아보시면 왜 메모리 접근 불가 가 되는지 알 수 있지 않을까요?
전 범인으로 몰고 계시는 2중벡터가 억울해 보이네요;
네..
감사합니다.
2중벡터를 범인으로 의심하는(?) 이유는
MSVC 2008 에서 코드를 돌려보고 class B 에서 초기화된 px 의 참조 형태를 보니
allocator 가
vector<vector<complex<double> > >
형태가 아닌complex<double>
의 형태로되어 있었기 때문입니다.
일단 이 문제를 우회하는 방법으로 다시 코딩중이긴 합니다만.. 왜 안되는지 정말 궁금하네요.
Leo.
뭔가 착각하시는 듯...
allocator라면
allocator<vector<complex<double> > >
아닌가요?allocator는 원소에 대해서 type 매개변수를 받을텐데요.
말씀하신대로라면 내부의 vector에 대한 allocator type 매개변수를 확인하신게 아닌가 싶네요.
중복삭제
윗글과 중복되었습니다.
A의 생성자
이렇게 되야 하지 않나요?
명시적으르 buffer 객체를 먼저 초기화 하고 그다음 b_module을 초기화...
Life rushes on, we are distracted
Life rushes on, we are distracted
그렇게 해도 안 됩니다.
생성(초기화)순서는 불만을 가지고 있는 사람들이 좀 있는 사안이지만 그렇다고 꼭 순서에 따라 하나하나 초기화하는 것도 성능에 문제가 될 수 있습니다.
VC2008, gcc 4.1.2 에서
VC2008, gcc 4.1.2 에서 테스트를 해보니 초기화 순서는 컴파일러가 알아서 맞춰주는 것 같습니다.
하지만 상당히 식은 땀 나는 초기화 순서임에는 많은 분들이 동의하실 것 같고요 암튼,
고민이 깊어지실 것 같아 식사 후 에 테스트를 해보았는데요
#include
template
struct Complex {
T a_, b_;
Complex(T a, T b) : a_(a), b_(b) {}
};
class B {
typedef std::vector > T_vec;
typedef std::vector T_mat;
public:
B(T_mat *px) { px->resize(10); }
};
class A {
typedef std::vector > T_vec;
typedef std::vector T_mat;
T_mat x;
B b;
public:
A() : b(&x) {}
void add() { T_vec tmpTV; tmpTV.push_back(Complex(1, 2) ); x[0] = tmpTV; }
};
int main()
{
A a;
a.add();
return 0;
}
쓰신 내용에 맞춰서 해본다고 했는데 위 코드는 실행에 문제가 없네요
아마도 제가 내용을 잘 못 파악하고 있는 것 같은데
실제 문제가 생기는 코드를 발췌해 주시거나 위 코드를 인용해서 의도를 다시 제시해주시면
저도 고민해볼께요
아 그리고 '꼭 순서에 따라 하나하나 초기화하는 것도 성능에 문제가 될 수 있습니다.'
이 부분에서 buffer() 는 직접 명시하지 않아도 컴파일러가 넣어주는 부분이니
코드량에 따른 성능을 얘기하시는 거라면 아닌 것 같고 초기화 순서에 따른 문제를 예방하는 측면에서는
오히려 원 코드보단 대단히? 좋은 코드가 아닐까요;
아아.. 감사합니다.
아아.. 감사합니다.
일단 원코드를 발췌해드리긴 어렵습니다. 곁가지가 달린 코드량이 엄청 많은데다
보안상 유출도 안됩니다. :(
사실 제가 올려드린 코드를 회사의 다른 분께서 테스트해보셨는데 이상없이 실행되더라 하셔서
참 난감했습니다.
가능한대로 원 문제가 발생하는 코드를 따로 만들어 보겠습니다. (가능할지 모르겠네요. ㅜㅠ)
Leo.
꼭 그렇게 하고 싶다면 상속을 쓰세요.
귀찮더라도 같은 class 내에서 한 member변수를 다른 member변수의 초기화과정에 넣고자 하신다면 상속을 쓰시면 원하시는대로 될 것 같습니다.
기반 class 부분이 파생 class 부분보다 먼저 생성되도록 되어 있으니까요.
기반 class 부분의 member 변수를 파생 class 부분의 member 변수의 생성자 매개변수로 활용하는 것은 올바른 방법입니다.
저라면 그냥 기본생성자로 생성하겠지만 말이죠.
아휴, 사용하지 않을 기반 class 만드는 귀찮음을 어떻게 하남?
제가 잘못 알고 있었군요.
좀 찾아봤는데 C++ 의 class member 변수 초기화 순서는 선언순서를 따른다고 하네요.
초기화목록에 명시한 순서와는 상관이 없다고 합니다.
따라서 발제자가 처음 작성하신 code에 문제가 있고, 그것이 초기화순서에 의한 것이라면
그것은 compiler의 문제입니다.
그 문제가 분명하다면 compiler를 바꾸시던가 compiler 문제를 피해갈 수 있는 방식으로 작성해야겠네요.
성능문제를 이야기한 것은 초기화순서를 분명히 하지 않고, 동시 초기화가 가능하게 되어 있는 줄 알았기 때문이었는데,
사실 병렬처리의 가능성은 compiler가 판단할 문제이므로 문제될 것이 없겠네요.
댓글 달기