У меня есть иерархия типов, похожая на приведенный ниже пример кода, и я пытаюсь создать их экземпляры с помощью шаблона фабрики (или, если быть педантичным, скорее шаблона построителя, поскольку моя фабрика получает входные данные из XML-документа... но я отступление).
Как бы я ни пытался это сделать, я сталкиваюсь с проблемами, которые, как я подозреваю, связаны либо с нарезкой, если я возвращаюсь по значению, либо с областью видимости, если я возвращаюсь по ссылке.
В приведенной ниже программе, например, segfaults на линии a.doA()
внутри C::doStuff()
. Если вместо этого я изменю вызов с value_C_factory<C>()
на ref_C_factory<C>()
, я получу пару предупреждений о «возвращении ссылки на временную», но программа компилируется, вместо этого segfaults на b.doB()
в следующей строке (без вывода чего-либо из a.doA()
.. .).
След от gdb
выглядит так: вторая строка — это та, что в моем коде, упомянутом выше.
#0 0x00007ffff7dbddb0 in vtable for std::ctype<char> () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1 0x00000000004010e9 in C::doStuff (this=0x7fffffffdd00) at syntax.cpp:57
#2 0x0000000000400cf2 in main () at syntax.cpp:95
Что вызывает эти segfaults? Это, как я подозреваю, нарезка/обзор в случае значения/ссылки? Если нет, то что это? И самое главное, как правильно построить свои экземпляры из входных данных?
Пример кода
Приведенный ниже код должен скомпилироваться и дать указанное выше поведение, например. GCC 4.8 с использованиемgcc -g -Wall -std=c++11 -o test test.cpp
(во всяком случае, я так делаю).
#include <iostream>
#include <typeinfo>
class IA {
public:
virtual void doA() const = 0;
virtual ~IA() { }
};
class A : public IA {
private:
std::string atask;
public:
explicit A(const std::string &task) : atask(task) {
std::cout << "Created A with task " << atask << std::endl;
}
void doA() const {
std::cout << "I did A! " << atask << std::endl;
}
};
class IB {
public:
virtual void doB() const = 0;
virtual ~IB() { }
};
class B : public IB {
private:
std::string btask;
public:
explicit B(const std::string &task) : btask(task) {
std::cout << "Created B with task " << btask << std::endl;
}
void doB() const {
std::cout << "I did B! " << btask << std::endl;
}
};
class IC {
public:
void doStuff() const;
virtual ~IC() { }
};
class C : public IC {
private:
const IA &a;
const IB &b;
public:
C(const IA &a, const IB &b) : a(a), b(b) { }
void doStuff() const {
a.doA(); // with value factory method, segfault here
b.doB(); // with reference factory, segfault here instead
}
};
template<typename TA>
TA value_A_factory() {
return TA("a value");
}
template<typename TB>
TB value_B_factory() {
return TB("b value");
}
template<typename TC>
TC value_C_factory() {
return TC(value_A_factory<A>(), value_B_factory<B>());
}
template<typename TA>
const TA &ref_A_factory() {
return TA("a ref");
}
template<typename TB>
const TB &ref_B_factory() {
return TB("b ref");
}
template<typename TC>
const TC &ref_C_factory() {
const TC &c(ref_A_factory<A>(), ref_B_factory<B>());
return c;
}
int main() {
C c = value_C_factory<C>();
std::cout << typeid(c).name() << std::endl;
c.doStuff();
}
const ref
, все будет в порядке. Но признаю, что я тут совсем запутался, так что вы, скорее всего, более правы, чем я. Однако, если я не по ссылке, не будет ли аргумент нарезан при передаче конструкторуC
? - person Tomas Aschan   schedule 02.04.2014const&
продлевает срок службы временного объекта. Это до конца выражения, в котором оно встречается (в вашем случае конструктор). После этого выражения временные файлы будут уничтожены, а ваши ссылки вC
будут болтаться. - person pmr   schedule 02.04.2014