假设我有一个带有多个构造函数的非可复制类,如下所示
class Foo: boost::noncopyable
{
public:
Foo(std::string s) {...}; // construct one way
Foo(int i) {...}; // construct another way
}
现在,我想构造一个对象,并选择在运行时使用哪个构造函数:
我可以用这样的指针做到: -
boost::shared_ptr<Foo> f;
if (condition)
f.reset(new Foo(myString));
else
f.reset(new Foo(myInteger));
// common code follows
f->doSomethingComplicated(...);
但这感觉很麻烦而且很慢。是否有一种简单的方法可以选择对象的构造函数而无需动态分配?
更多详情:上面的Foo
课只是为了说明问题。所涉及的实际课程是Windows Gdiplus::Bitmap
- http://msdn.microsoft.com/en-gb/library/windows/desktop/ms534420(v=vs.85).aspx
答案 0 :(得分:2)
您可以在堆栈上使用C ++ 11,而无需放置新的并且没有可用的复制/移动构造函数/赋值。观察:
auto factory = [&]() -> Foo
{
if (condition) {
return { myString };
} else {
return { myInteger };
}
};
Foo&& foo = factory();
foo.doSomethingComplicated();
仿函数和Foo实例将在堆栈上幸福地生活,没有分配(可能除了在Foo
的构造函数中复制字符串)。当Foo超出范围时,Foo会调用它的析构函数。取胜。
使用统一初始化构造返回值时,不涉及复制/移动操作。请注意,返回myString
(隐式转换)或Foo(myString)
会强制编译器检查对象是否可复制/可移动,即使可以省略此类复制/移动。
编辑:或者,这可以做得更短,但更多一点&#34;神奇&#34;:
Foo&& foo = [&]() -> Foo
{
if (condition) {
return { myString };
} else {
return { myInteger };
}
}();
编辑:Pre-C ++ 11,Visual Studio hacky解决方案:
当使用隐式转换构造函数从函数返回值时,VC似乎无法检查对象是否可复制。所以这是有效的,即使它违反了标准:
Foo make_foo(bool condition, const std::string&s, int i)
{
if ( condition) {
return s;
} else {
return i;
}
}
然后就这样使用它:
Foo& f = make_foo(condition, myString, myInteger);
请注意,这是另一个VC hack,因为根据标准临时不能分配给对可变对象的引用,即需要更改const Foo&
,这将是非常有限的这里。
不是说你应该这样处理它,但它是可能的。
答案 1 :(得分:1)
你的设计存在缺陷。 &#39; Foo&#39;将类型elision委托给类的用户。看看boost :: any(http://www.boost.org/doc/libs/1_55_0/doc/html/any.html)
答案 2 :(得分:1)
我认为满足您的要求(不是动态分配,不可复制,前C ++ 11)的最佳选择是使用placement new
。
请参阅here以获取简短示例。
boost::optional
对你来说也可能是一个可接受的选项(它基本上只是在内部为你做这件事,以及跟踪对象是否已被初始化)。就optional
imo。
答案 3 :(得分:0)
保持小而简单,我会说。如果这是一个非常本地化的问题,为什么不重复这个电话?
if (condition)
{
Foo f(myString);
f.doSomethingComplicated();
}
else
{
Foo f(myInt);
f.doSomethingComplicated();
}
如果这不可行,请将Foo
指针(或智能指针)包装在新类中。
class FooWrapper // copyable
{
private:
boost::shared_ptr<Foo> m_foo;
public:
FooWrapper(std::string const &s) : m_foo(new Foo(s)) {}
FooWrapper(int i) : m_foo(new Foo(i)) {}
void doSomethingComplicated() { m_foo->doSomethingComplicated(); }
};
FooWrapper foo = condition ? FooWrapper(myString) : FooWrapper(myInt);
foo.doSomethingComplicated();
答案 4 :(得分:0)
使用C ++ 11,您可以:
Foo&& f = condition ? Foo{myInteger} : Foo{myString};
f.doSomethingComplicated();
通过使用r值引用,可以避免使用常量,并且仍然可以延长临时值。
答案 5 :(得分:0)
如果你只需要构造一个临时对象,我认为你可以使用三元表达式将它绑定到一个const引用:
const Foo &f(condition ? Foo(myString) : Foo(myInteger));
f.doSomethingComplicated(...);