我无法理解结构如何替换typedef

时间:2016-12-07 13:14:42

标签: c++ c++14

请看这个链接:https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(C4503)&rd=true建议写:

// C4503b.cpp  
// compile with: /W1 /EHsc /c  
#include <string>  
#include <map>  

class Field{};  
struct Screen2 {  
   std::map<std::string, Field> Element;  
};  

struct WebApp2 {  
   std::map<std::string, Screen2> Element;  
};  

struct WebAppTest2 {  
   std::map<std::string, WebApp2> Element;  
};  

struct Hello2 {  
   std::map<std::string, WebAppTest2> Element;  
};  

Hello2 MyWAT2;  

而不是

// C4503.cpp  
// compile with: /W1 /EHsc /c  
// C4503 expected  
#include <string>  
#include <map>  

class Field{};  

typedef std::map<std::string, Field> Screen;  
typedef std::map<std::string, Screen> WebApp;  
typedef std::map<std::string, WebApp> WebAppTest;  
typedef std::map<std::string, WebAppTest> Hello;  
Hello MyWAT; 

但是这些代码与typedef Hellostd::map不等同,而struct s只是一个结构,其字段为map这意味着我不能互换使用它们。有人可以解释这个伎俩吗?

4 个答案:

答案 0 :(得分:4)

你是对的,你不能互换使用它们。实际上,Microsoft建议您这样做是为了克服技术上的困难:他们无法(或有困难)处理超过4096字节的错位名称。

在大多数情况下,我相信typedef对聚合来说是更好的解决方案。

但是由于你的编译器有些限制,你可能会陷入困境。

答案 1 :(得分:3)

如果你想要一个能够实现区分(受损,可能被截断)名称的目标的解决方案,但没有额外的命名层的缺点,你可以使用继承:

class Screen : public std::map<std::string, Field>
{
    // forward constructors here
};

答案 2 :(得分:0)

提供的变通方法不是作为重现器的等效替代品,而是作为可能的方式来减少导出符号的修饰长度。

您可以使用简单objdump /symbols objfile.obj验证使用typedef s的装饰符号的长度比分成struct的类似对应长度要长得多(Microsoft编译器历来使用过专有名称修改方案)。

答案 3 :(得分:0)

typedef没有声明新类型,它只是一个别名。如果你转发声明typedef,当编译器看到typedef定义时,它会引发错误:

// a.hpp
class Screen;

class any_class_using_screen {};

// a.cpp
#include "a.hpp"

typedef std::map<std::string, Field> Screen; // Error.

使用简单的继承允许您将自定义名称用于其他类型:

class Screen : public std::map<std::string, Field>
{};

请记住,没有其他成员的简单继承不会导致任何内存或时间开销。这与typedef一样有效,并且它是一种新类型。

由于std::map<...>没有虚拟析构函数,因此不能使用&#34;指针指向基类&#34;当然,像往常一样。 Screen实例的所有者(创建screen实例的实例),如果它存在于堆中并且必须被破坏,则必须从指向派生类的指针中删除:

template<class K, class V>
void f(std::map<K, V> const* map); // Do something

int main()
{
    Screen* s = new Screen;
    f(s); // Ok
    delete s; // OK, deleting from derivate class
}

@ PeterA.Scheneider建议,就派生类没有其他成员而言,没有任何反应,你可以从指向派生类的指针调用析构函数。但是,theoretically,没有虚拟析构函数,你正在破坏基类实例(只有基类生命到达它的结尾),并且派生类实例仍然存在,具有死基,具有损坏的对象。从实际的角度来看,我认为对象被正确破坏了,但无论如何我都不知道这是否会导致不确定的行为。

应该检查标准以确定。

此外,从基类指针破坏没有额外成员的派生对象的方法可能存在对齐问题。

如果基类没有虚拟析构函数,那么在没有&#34;多态意图&#34;的情况下继承,并且总是从派生类最多的类中进行析构。