我不明白为什么“返回c“因为我们知道我们可以在构造函数定义中返回一个对象,所以不在复制构造函数定义中工作。 [英] I am not getting why " return c" not working in copy constructor definition as we know that we can return an object in constructor definition.

查看:75
本文介绍了我不明白为什么“返回c“因为我们知道我们可以在构造函数定义中返回一个对象,所以不在复制构造函数定义中工作。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  #include   <     iostream    >  
#include < string >
#include < cstring >
使用 namespace std;
class string1
{
char * name;
int 长度;

public
string1()
{
length = 0 ;
name = new char [length + 1 ];
}

string1( char const * s)
{
length = strlen(s);
name = new char [length + 1 ];
strcpy(name,s);
}

void display( void
{
cout<<名称<< ENDL;
}

~string1();
int join( const string1& a, const string1& b);
};

int string1 :: join( const string1& a, const string2& b)
{
string1 c;
c.length = a.length + b.length;
删除名称;
c.name = new char [c.length + 1 ];
strcpy(c.name,a.name);
strcat(c.name,b.name);
return c;
}

string1 :: ~string1()
{
delete name;
}

int main()
{
char const * str1 = myname ;
string1 name1(str1);
string1 name2( anupam);
string1 name3( sinha);
string1 s1;
string1 s2;
s1.join(name1,name2);
s2.join(s1,name3);
name1.display();
name2.display();
name3.display();
s1.display();
s2.display();
}

解决方案

我认为你指的是这个功能:

  int  string1 :: join( const  string1& a, const  string2& b)
{
string1 c;
c.length = a.length + b.length;
删除名称;
c.name = new char [c.length + 1 ];
strcpy(c.name,a.name);
strcat(c.name,b.name);
return c;
}



这不是复制构造函数,而是一个简单的成员函数。它是唯一包含return c语句的函数,所以你必须指的是它。



最明显的原因是它不起作用的是join函数返回一个int,但你的变量c是一个string1。所以我们假设您打算写一下:

 string1 string1 :: join( const  string1 & a, const  string2& b)



在这种情况下,join函数不应该改变对象它被调用,但只是连接a和b并返回结果。那么你实际上应该将join声明为静态函数,因为它不需要类对象。

  class  string1 
{
...
static string1 join( const string1& a, const string2& b);
...



您还应该更正删除语句,该语句应为:

  delete  [] c.name; 





另一种方法是将a和b的连接分配给字符串,您可以将其称为join。主函数中的测试代码实际上表明这是你的意图。然后join函数根本不需要string1 c,应该读取:

  void  string1 :: join( const  string1& a, const  string2& b)
{
length = a.length + b.length;
delete [] name;
name = new char [c.length + 1 ];
strcpy(name,a.name);
strcat(name,b.name);
}





此外,变量 name 的命名不是非常聪明,因为字符串不仅可能包含名称,还包含所有类型的东西。缓冲区可能是一个更好的名称。



其余代码包含另一个错误:默认构造函数不初始化1字节的分配缓冲区。 />


希望能帮到你。


除了nv3所说的,每当你做任何低级资源管理任务时这(你基本上管理一个可变大小的字符数组)确保你考虑异常安全。



看看nv的修改:



  void  string1 :: join( const  string1& a, const  string2& b)
{
length = a.length + b.length;
delete [] name;
name = new char [c.length + 1 ];
strcpy(name,a.name);
strcat(name,b.name);
}





问问自己如果,你调用函数的对象会发生什么?新的抛出?答案是你最终会得到一个具有棘手状态的对象 - 长度表明有一个有效的字符串,但是它有一个指向一些已删除内存的指针。啊。让恢复变得不可能,你必须把对象分开。



如何解决这个问题在SA的答案中暗示:写一个构造函数。一个方便的指南是在构造函数中执行所有 new ,并在析构函数中执行所有 delete 。您将无法一直管理它,但在编码时请记住这是一个方便的规则。



为什么?如果构造函数失败,则对象永远不存在,并且程序状态的其余部分可以保持不变。这使得恢复或报告错误变得容易得多 - 除了正在构建的对象之外,你没有加扰任何东西。



那你怎么能实现使用构造函数加入?首先写一个两个参数的构造函数:



 string1( const  string1& a, const  string1& b)
{
length_ = a.length + b.length;
data_ = new char [length + 1 ];
std :: copy(a.name,a.name + a.length,name);
std :: copy(b.name,b.name + b.length_,name + a.length);
name [length] = 0 ;
}





然后定义交换功能:



  void  swap(string1& swap_with)
{
std :: swap(length,swap_with.length) ;
std :: swap(name,swap_with.name);
}





和你的加入成为:



  void  join( const  string1& a, const  string1& b)
{
string1 temp(a,b);
swap(temp);
}





如果构造函数出现严重错误,原始对象仍然完好无损且处于可用状态,欢呼!



此副本和交换在其他地方也很有用 - 例如当你在编写赋值运算符时 - 所以在你的脑海中修复它并不浪费任何C ++程序员的时间。



PS:回复评论。 ..



您对加入的抱负似乎是 + = 在大多数字符串实现中。您可以使用两个参数构造函数和swap来完成它:



  void  join( const  string1& to_append)
{
string1 temp(* this ,to_append);
swap(temp);
}





Scally相似不是吗?



基本上整理构造函数,析构函数和非抛出交换,大多数复制操作变得轻而易举 - 异常安全。


这是因为构造函数代码不返回任何内容,它没有返回类型;这是故意设计的,以避免这种情况。



构建时,你总是使用隐式参数this(你可以明确地使用它,有时候有这样做,以避免命名冲突),就像使用非构造函数实例函数完成一样。此参数表示指向正在构造的对象的指针。构造的目的是以某种必要的方式修改由该指针访问的对象。对构造函数的调用返回对象并将结果赋值给l值,或者,如果在构造函数调用中使用运算符 new ,则返回this指针本身;在这种情况下,对象在堆上分配,分配本身可以自定义,这是一个完全不同的故事。



-SA

#include< iostream > 
#include< string >
#include< cstring >
using namespace std;
class string1
{
  char *name;
  int length;

public:
  string1 ()
  {
    length = 0;
    name = new char[length + 1];
  }
 
  string1 (char const *s)
  {
    length = strlen (s);
    name = new char[length + 1];
    strcpy (name, s);
  }

  void display (void)
  {
    cout << name << endl;
  }

  ~string1();
  int join (const string1 &a, const string1 &b);
};

int string1::join (const string1 &a, const string2 &b)
{
  string1 c;
  c.length = a.length + b.length;
  delete name;
  c.name = new char[c.length + 1];
  strcpy (c.name, a.name);
  strcat (c.name, b.name);
  return c;
}

string1 :: ~string1()
{
  delete name ;
}

int main ()
{
  char const *str1 = "myname ";
  string1 name1 (str1);
  string1 name2 ("anupam ");
  string1 name3 ("sinha ");
  string1 s1;
  string1 s2;
  s1.join (name1, name2);
  s2.join (s1, name3);
  name1.display ();
  name2.display ();
  name3.display ();
  s1.display ();
  s2.display ();
}

解决方案

I think you are referring to the function:

int string1::join (const string1 &a, const string2 &b)
{
  string1 c;
  c.length = a.length + b.length;
  delete name;
  c.name = new char[c.length + 1];
  strcpy (c.name, a.name);
  strcat (c.name, b.name);
  return c;
}


which is no copy constructor, but a simple member function. It is the only function containing the "return c" statement, so you must be referring to that.

The most obvious reason why this can't work is that the join function returns an int, but your variable c is a string1. So let's assume for a moment that you meant to write:

string1 string1::join (const string1 &a, const string2 &b)


In that case the join function should not alter the object it is called for, but simply concattenate a and b and return the result. Then you should actually declare join as a static function, as it does not need a class object.

class string1
{
  ...
  static string1 join (const string1& a, const string2& b);
  ...


You should also correct the delete statement, which should read:

delete [] c.name;



The other alternative is to assign the concattenation of a and b to the string, which you call join on. The test code in your main function actually shows that this was your intention. Then the join function does not need a string1 c at all and should read:

void string1::join (const string1 &a, const string2 &b)
{
  length = a.length + b.length;
  delete [] name;
  name = new char[c.length + 1];
  strcpy (name, a.name);
  strcat (name, b.name);
}



Besides, the naming of variable name is not very clever, as a string may contain not only names, but all kind of things. Buffer would probably a better name for it.

And the rest of your code contains another bug: The default constructor does not initialize the allocated buffer of 1 byte.

Hope that helps you out.


In addition to what nv3 said, whenever you're doing any low level resource management task like this (you're essentially managing a variable sized array of characters) make sure you take exception safety into account.

Looking at nv's modifications:

void string1::join (const string1 &a, const string2 &b)
{
  length = a.length + b.length;
  delete [] name;
  name = new char[c.length + 1];
  strcpy (name, a.name);
  strcat (name, b.name);
}



ask yourself what happens to the object you've called the function on if the new throws? The answer is you'll end up with the object having a screwy state - the length suggests that there's a valid string but it's got a pointer to some deleted memory. Ugh. Makes recovery impossible and you have to bin the object.

How to get around this is hinted in SA's answer: Write a constructor. A handy guideline is do all news in a constructor and all deletes in the destructor. You won't be able to manage it all the time but it's a handy rule to keep in mind when you code.

Why? If constructors fail then the object never exists and the rest of the program state can stay the same. That makes it far easier to recover or report errors - you haven't scrambled anything apart from the object you were constructing.

So how could you implement join using a constructor? Well first off write a two argument constructor:

string1( const string1 &a, const string1 &b )
{
	length_ = a.length + b.length;
	data_ = new char[ length + 1 ];
	std::copy( a.name, a.name + a.length,  name            );
	std::copy( b.name, b.name + b.length_, name + a.length );
	name[ length ] = 0;
}



Then define a swap function:

void swap( string1 &swap_with )
{
	std::swap( length, swap_with.length );
	std::swap( name,   swap_with.name   );
}



and your join becomes:

void join( const string1 &a, const string1 &b )
{
	string1 temp( a, b );
	swap( temp );
}



If the constructor goes horribly wrong your original object is still intact and in a usable state, hurrah!

This copy and swap is useful in other places as well - e.g. when you're writing assignment operators - so getting it fixed in your mind isn't a waste of time for any C++ programmer.

PS: In reply to comment...

Your ambition for join seems to be += in most string implementations. You can do it with the two argument constructor and swap:

void join( const string1 &to_append )
{
	string1 temp( *this, to_append );
	swap( temp );
}



Scarily similar isn't it?

Basically sort out the constructors, a destructor and non-throwing swap and most copying operations become a doddle - and exception safe as well.


This is because constructor code don't return anything, it does not have return type; this is designed so on purpose, to avoid such situations.

While constructing, you always work with the implicit parameter "this" (which you can use explicitly and sometime had to do so, to avoid naming conflicts), exactly as it is done with non-constructor instance functions. This parameter represents the pointer to the object being constructed. The purpose of construction is to modify the object accessed by this pointer in some required way. The call to a constructor returns the object and assigns the result to l-value, or, if the operator new is used in the constructor call, "this" pointer itself is returned; in this case, the object is allocated on heap, and allocation itself can be customized, which is a whole different story.

—SA


这篇关于我不明白为什么“返回c“因为我们知道我们可以在构造函数定义中返回一个对象,所以不在复制构造函数定义中工作。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆