C++ 映射、引用、指针和内存分配
我在map和valuetype分配方面有点困难C++ 映射、引用、指针和内存分配,c++,memory,reference,map,pointers,C++,Memory,Reference,Map,Pointers,我在map和valuetype分配方面有点困难 std::make_pair(0, *c) 考虑这个简单的类: class Column { private: char *m_Name; public: // Overrides const char *Name(){ return this->m_Name; } // Ctors Column(const char *NewName){ this->
std::make_pair(0, *c)
考虑这个简单的类:
class Column {
private:
char *m_Name;
public:
// Overrides
const char *Name(){
return this->m_Name;
}
// Ctors
Column(const char *NewName){
this->m_Name = new char[strlen(NewName) + 1];
strcpy(this->m_Name, NewName);
}
// Dtors
~Column(){
cout << "wtf?\n";
delete this->m_Name;
}
};
类列{
私人:
char*m_名称;
公众:
//覆盖
常量字符*名称(){
返回此->m_名称;
}
//演员
列(常量字符*新名称){
这个->m_Name=newchar[strlen(NewName)+1];
strcpy(此->m_名称,新名称);
}
//DTOR
~Column(){
库姆名字;
}
};
现在我有了这张地图:
// Typedefs
typedef std::map<int, Column> ColumnContainer;
ColumnContainer *m_Container;
//Typedefs
typedef std::映射列容器;
柱状容器*m_容器;
当我称之为:
Column *c = new Column("Test");
cout << "CREATED: " << c->Name() << "\n";
it = this->m_Container->insert(std::make_pair(0, *c)).first;
cout << "AGAIN: " << c->Name() << "\n";
Column*c=新列(“测试”);
cout-insert(std::make_-pair(0,*c))。首先;
cout为什么不使用std::string
作为列名?真正地然后一切都好了
因为这里有很多问题。。。从析构函数开始(当分配由new[]
完成时,使用delete[]
)
另外,你真的需要用new创建你的专栏吗
让我们重写一下:
class Column
{
public:
Column() : m_name() {}
Column(const std::string& name) : m_name(name) {}
const std::string& getName() const { return m_name; }
private:
std::string m_name;
};
现在是插入代码:
std::map<int,Column> m_container;
Column myColumn = Column("Test");
std:cout << "CREATED: " << myColumn.getName() << std::endl;
m_container[0] = myColumn; // COPY the column
std::cout << "AGAIN: " << myColumn.getName() << std::endl;
C++已经需要大量的代码膨胀,让我们尽可能使用它提供的快捷方式。容器中的m_名称应该是字符串,因此可以将其复制构建到映射中
现在您没有定义正确的复制构造函数,所以它只是将m_名称复制为指针,这是无效的
试着做一些简单的事情
class Column {
private:
std::string m_Name;
public:
// Overrides
const char *Name(){
return m_Name.c_str();
}
};
由于C++,所有成员都是可复制的,所以可以获得复制构造函数。
你看到的是,一个列的临时拷贝被销毁了。如果插入构造函数,您应该会看到正在创建的副本。make\u pair(0,*c)
创建一个(临时的、未命名的)对。该对通过引用传递给map::insert
,由于std::map
拥有其元素,因此它会复制该对。然后,临时对被销毁,销毁它包含的列对象
这就是为什么有必要为要用作标准容器元素的类型正确定义复制构造。字符串m_名称没有第二次打印的根本原因是STL构建映射的方式。在插入过程中,它会对值进行各种复制。因此,m_Name在原始列的一个副本中被销毁
另一条建议是,当对象是映射中的值时,使用指向对象的指针。否则,如果对象足够大,可能会对性能造成重大影响。代码中发生了什么:
在这里,您将动态创建一个对象。(这不会在您的代码中释放)。
你为什么用指针?(智能指针是你的朋友。)
但普通物体更可取
Column *c = new Column("Test");
现在,在将对象复制到std::pair类型的临时对象中时,创建对象的副本(这使用列的复制构造函数创建M_name成员的副本(现在有两个指向同一内存位置的指针))
现在将这对插入到地图中。这是通过再次使用列复制构造函数来完成的(它使用调用列复制构造函数的make_pair copy构造函数)。再次将M_name指针复制到此对象中。现在有三个对象指向动态分配的字符串
m_Container->insert( pairObject )
此时,通过调用std::make_pair()创建的临时对象不再需要,因此它将被销毁。这就是调用析构函数的地方。当然,这会给您留下两个对象,它们的指针指向现在已释放的内存
你有个大问题。
您需要使用std::string(首选解决方案)
或者,您需要在类中正确处理原始拥有的指针。这意味着您需要实现所有四个默认生成的方法:
- 建造师
- 自毁者
- 复制构造函数
- 赋值运算符
小问题:
你需要停止像java程序员那样编码
Column *c = new Column("Test");
it = this->m_Container->insert(std::make_pair(0, *c)).first;
应该是这样的:
m_Container[0] = Column("Test");
无需动态分配所有内容。
事实上,这是非常危险的
解释为什么拥有原始指针是个坏主意。
这个看起来不错。但是编译器也为您生成了两个方法。在mnost情况下,这很好,但当您拥有原始指针时就不行了
X::X(X const& copy)
:m_name(copy.m_name)
{}
X& X::operator=(X const& copy)
{
m_name = copy.m_name;
}
现在想象一下代码:
X x("Martin");
X y(x);
“x”和“y”现在都包含指向同一内存块的指针(m_name)。当“y”超出范围时,它调用其derstructor,该derstructor调用内存上的delete[]。现在“x”超出范围,在同一块内存上调用delete
Z z("Bob");
z = x;
与上述问题相同,jsut使用不同的运算符
这对你有何影响?
您正在使用指向列的指针映射。地图实际上存储了一个Column对象。因此,它使用上面的复制构造函数来复制对象。所以有一个问题。但在代码中也有很多次创建和传递临时对象
doWork(Column const& x) { /* Do somthing intersting */
doWork(Column("Hi There"));
这里我们创建一个临时列对象,该对象被传递到doWork()。完成doWork()后,temporay将超出范围并被删除。但是,如果doWork()使用copy costructor或assignment操作符复制对象,会发生什么情况?这就是将对象插入地图时发生的情况。您正在创建一个临时对,然后将该值复制到映射中。然后将销毁此临时对。您不需要使用This指针来引用成员数据,除非您希望清除同名对象的任何歧义。“this->”已经暗示。例如,你可以说:“delete m_Name;”是的,我只是喜欢使用这个关键字。你能为我详细说明一下吗?但是myColumn不是在堆栈上创建的吗?是的,但是当你把它放在地图上时,你会复制它,这有关系吗?哟
Z z("Bob");
z = x;
doWork(Column const& x) { /* Do somthing intersting */
doWork(Column("Hi There"));