我知道返回临时引用是违法的,但这是我的问题:
const stringSet & Target::dirList( const dirType type ) const
{
switch( type )
{
case SOURCE_DIR:
return m_sourceDirs;
case HEADER_DIR:
return m_headerDirs;
case RESOURCE_DIR:
return m_resourceDirs;
default:
return stringSet(); // PROBLEM HERE!
}
}
前三个选项返回对stringSet
数据成员的const引用。我应该怎么做默认情况?如果我把它遗漏,编译器(GCC与-Wall -Wextra -pedantic
)抱怨并且我不想要它,因为这些选项倾向于以最奇怪的方式捕捉我的床设计选择:)
谢谢!
答案 0 :(得分:9)
将默认设置保留为成员...并返回对它的引用。当然,如果默认情况在理论上是可行的。如果不是,则抛出异常而不返回任何内容。
default:
throw invalid_argument_exception();
答案 1 :(得分:4)
const stringSet & Target::dirList( const dirType type ) const
{
static const stringSet defaultSet; // <--
switch( type )
{
case SOURCE_DIR:
return m_sourceDirs;
case HEADER_DIR:
return m_headerDirs;
case RESOURCE_DIR:
return m_resourceDirs;
default:
return defaultSet; // <--
}
}
答案 2 :(得分:0)
您无法返回对在堆栈上创建的临时对象的引用。我将在你的函数返回时被销毁,你的应用程序将崩溃。
如果您打算做类似的事情,您将不得不按价值而不是通过参考来回报,即
stringSet Target::dirList( const dirType type ) const
这显然会影响性能,因为很可能最终会为其他引用调用复制构造函数。另一种方法是避免在堆栈上创建临时对象。根据您的应用程序,您可以通过多种方式执行此操作,例如使用一个简单的池来获取临时对象,并在某些时候进行垃圾收集,或者您可以让dirList获取正在填充的stringSet参数通过你的功能。
最好的情况 - 你不能只在某个地方设置永久默认设置吗?每次通话都必须是唯一的吗?
答案 3 :(得分:0)
不一定总是正确的选项,但是为了它值得你可以使用shared_ptr - 用null删除器构造一个shared_ptr并返回如果字符串集已经存在,否则构造一个指向空集并且具有正常的删除并返回。换句话说:
#include <set>
#include <string>
#include <boost/shared_ptr.hpp>
struct NullDeleter
{
void operator()(void *p) {}
};
enum DirType
{
SOURCE_DIR,
HEADER_DIR,
RESOURCE_DIR,
OTHER,
};
typedef std::set<std::string> StringSet;
typedef boost::shared_ptr<const StringSet> StringSet_CPtr;
struct Target
{
StringSet m_sourceDirs, m_headerDirs, m_resourceDirs;
Target()
{
m_sourceDirs.insert("/source");
m_headerDirs.insert("/header");
m_resourceDirs.insert("/resources");
}
StringSet_CPtr dir_list(DirType type)
{
switch(type)
{
case SOURCE_DIR:
return StringSet_CPtr(&m_sourceDirs, NullDeleter());
case HEADER_DIR:
return StringSet_CPtr(&m_headerDirs, NullDeleter());
case RESOURCE_DIR:
return StringSet_CPtr(&m_resourceDirs, NullDeleter());
default:
return StringSet_CPtr(new StringSet);
}
}
};
int main()
{
Target t;
StringSet_CPtr sourceDirs = t.dir_list(SOURCE_DIR),
headerDirs = t.dir_list(HEADER_DIR),
resourceDirs = t.dir_list(RESOURCE_DIR),
otherDirs = t.dir_list(OTHER);
return 0;
}
答案 4 :(得分:0)
有一些指令可以放在一个不可能的案例默认处理程序中,说它无法访问。编译器特定和非可移植,但大多数编译器都有。我只是不记得GCC是如何解释的。
编辑找到了语法...
switch (whatever)
{
case blah :
...;
break;
default :
__builtin_unreachable ();
}
正如我所说,这是一个特定于GCC的功能 - 但是有一个不同拼写的Visual C ++等价物。
BTW - 总是return *((stringSet*) 0);
。
编辑或抛出异常。
无论哪种方式(例外情况除外),只有当你确实确定它永远不会发生时。
答案 5 :(得分:-2)
如果我理解正确..........
以下是我使用这种开关的方法
关于此代码的两个注释:
我讨厌使用“&amp;” ref并且更喜欢“* const”(更可读),所以请调整。它本质上是一样的。
2.没有测试此代码。
const stringSet * const
Target::dirList( const dirType type ) const
{
const stringSet * pRet = NULL;
switch( type )
{
case SOURCE_DIR:
stringSet = m_sourceDirs;
case HEADER_DIR:
stringSet = m_headerDirs;
case RESOURCE_DIR:
stringSet = m_resourceDirs;
}
return pRet;
}