我试图赶上C ++并遇到一些我无法找到解决方案的问题。我正在使用一个类是std :: string的简单版本,这个类仅用于测试/学习目的'。谁可以帮我提出一些关于我做错事的建议。
问题简短:
我创建了一个带有复制构造函数和析构函数的类Str。 直接初始化没有问题。
Str a = "Hello"; // OK.
作业失败;
Str a;
a = "Hello"; // Failing.
下面提供了代码的反汇编以及出错的标识(根据我)。
注意:a = Str的版本(" Hello");显示同样的效果。
我知道出了什么问题,但我不知道如何纠正它。 在第一种情况下
Str a = "Hello";
// The constructor Str::Str(const char* value) is used. No problem.
在第二种情况下
Str a;
// The default constructor Str::Str() is used. No problem.
a = "Hello";
// 001D1557: The constructor Str::Str(const char* value) is used creating instance a'. No problem.
// 001D155C: Instance a' is copied over a. No problem yet.
// 001D157D: The desctuctor for a' is called, which in the process destoys the char* used by a, corrupting it.
我在这里做错了什么?我是否在关于如何分配值的C ++语义上遗漏了一些内容?
这是我使用的实际代码。
#pragma once
namespace Steenveld {
namespace Base {
class Str {
public:
Str();
Str(const Str& value);
Str(const Str* value);
Str(const char* value);
~Str();
inline const size_t& Length() const { return length; };
inline const char* Value() const { return buffer; };
private:
char* buffer;
size_t length;
size_t size;
void Init(void);
void SetBuffer(size_t size);
};
} // namespace Base
} // namespace Steenveld
及其实施:
#include "stdafx.h"
namespace Steenveld {
namespace Base {
Str::Str() {
Init();
}
Str::Str(const Str& value) {
Init();
length = value.length;
SetBuffer(length+1);
strcpy_s(buffer, size, value.buffer);
}
Str::Str(const Str* value) {
Init();
length = value->length;
SetBuffer(length+1);
strcpy_s(buffer, size, value->buffer);
}
Str::Str(const char* value) {
Init();
if (value != nullptr) {
length = strlen(value);
SetBuffer(length+1);
strcpy_s(buffer, size, value);
}
}
Str::~Str() {
if (buffer != nullptr) {
free(buffer);
buffer = nullptr;
size = 0;
length = 0;
}
}
void Str::Init(void) {
buffer = nullptr;
length = 0;
size = 0;
}
void Str::SetBuffer(size_t size) {
if (size <= 0) return;
if (buffer == nullptr) {
buffer = (char*)malloc(size);
this->size = size;
} else if (this->size < size) {
buffer = (char*)realloc(buffer, size);
this->size = size;
}
buffer[size-1] = '\0';
}
} // namespace Base
} // namespace Steenveld
VS2010头文件
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
#pragma once
#include "targetver.h"
#include <iostream>
#include <tchar.h>
#include "Str.h"
和实际的节目。
#include "stdafx.h"
using namespace Steenveld::Base;
int _tmain(int argc, _TCHAR* argv[])
{
Str a;
a = "Hell";
std::cout << a.Value() << "\r\n";
char n;
std::cin.get(n);
return 0;
}
程序部分的反汇编。
--- e:\andre\ontwikkeling\libconsole\consolenative\program.cpp -----------------
// ConsoleNative.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
using namespace Steenveld::Base;
int _tmain(int argc, _TCHAR* argv[])
{
001D1500 push ebp
001D1501 mov ebp,esp
001D1503 push 0FFFFFFFFh
001D1505 push offset __ehhandler$_wmain (1D5718h)
001D150A mov eax,dword ptr fs:[00000000h]
001D1510 push eax
001D1511 sub esp,100h
001D1517 push ebx
001D1518 push esi
001D1519 push edi
001D151A lea edi,[ebp-10Ch]
001D1520 mov ecx,40h
001D1525 mov eax,0CCCCCCCCh
001D152A rep stos dword ptr es:[edi]
001D152C mov eax,dword ptr [___security_cookie (1D9000h)]
001D1531 xor eax,ebp
001D1533 push eax
001D1534 lea eax,[ebp-0Ch]
001D1537 mov dword ptr fs:[00000000h],eax
Str a;
001D153D lea ecx,[ebp-1Ch]
001D1540 call Steenveld::Base::Str::Str (1D100Ah)
001D1545 mov dword ptr [ebp-4],0
a = "Hell";
001D154C push offset string "Hell" (1D7740h)
001D1551 lea ecx,[ebp-108h]
001D1557 call Steenveld::Base::Str::Str (1D1037h)
001D155C mov eax,dword ptr [ebp-108h]
001D1562 mov dword ptr [ebp-1Ch],eax
001D1565 mov ecx,dword ptr [ebp-104h]
001D156B mov dword ptr [ebp-18h],ecx
001D156E mov edx,dword ptr [ebp-100h]
001D1574 mov dword ptr [ebp-14h],edx
001D1577 lea ecx,[ebp-108h]
001D157D call Steenveld::Base::Str::~Str (1D1113h)
std::cout << a.Value() << "\r\n";
001D1582 push offset string "\r\n" (1D773Ch)
001D1587 lea ecx,[ebp-1Ch]
001D158A call Steenveld::Base::Str::Value (1D1104h)
001D158F push eax
001D1590 mov eax,dword ptr [__imp_std::cout (1DA33Ch)]
001D1595 push eax
001D1596 call std::operator<<<std::char_traits<char> > (1D116Dh)
001D159B add esp,8
001D159E push eax
001D159F call std::operator<<<std::char_traits<char> > (1D116Dh)
001D15A4 add esp,8
char n;
std::cin.get(n);
001D15A7 mov esi,esp
001D15A9 lea eax,[ebp-25h]
001D15AC push eax
001D15AD mov ecx,dword ptr [__imp_std::cin (1DA340h)]
001D15B3 call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::get (1DA330h)]
001D15B9 cmp esi,esp
001D15BB call @ILT+430(__RTC_CheckEsp) (1D11B3h)
return 0;
001D15C0 mov dword ptr [ebp-0F4h],0
001D15CA mov dword ptr [ebp-4],0FFFFFFFFh
001D15D1 lea ecx,[ebp-1Ch]
001D15D4 call Steenveld::Base::Str::~Str (1D1113h)
001D15D9 mov eax,dword ptr [ebp-0F4h]
}
001D15DF push edx
001D15E0 mov ecx,ebp
001D15E2 push eax
001D15E3 lea edx,[ (1D1610h)]
001D15E9 call @ILT+160(@_RTC_CheckStackVars@8) (1D10A5h)
001D15EE pop eax
001D15EF pop edx
001D15F0 mov ecx,dword ptr [ebp-0Ch]
001D15F3 mov dword ptr fs:[0],ecx
001D15FA pop ecx
001D15FB pop edi
001D15FC pop esi
001D15FD pop ebx
001D15FE add esp,10Ch
001D1604 cmp ebp,esp
001D1606 call @ILT+430(__RTC_CheckEsp) (1D11B3h)
001D160B mov esp,ebp
001D160D pop ebp
001D160E ret
001D160F nop
001D1610 db 02h
001D1611 db 00h
001D1612 db 00h
001D1613 db 00h
001D1614 db 18h
001D1615 db 16h
001D1616 db 1dh
001D1617 db 00h
001D1618 db e4h
001D1619 db ffh
001D161A db ffh
001D161B db ffh
001D161C db 0ch
001D161D db 00h
001D161E db 00h
001D161F db 00h
001D1620 db 32h
001D1621 db 16h
001D1622 db 1dh
001D1623 db 00h
001D1624 db dbh
001D1625 db ffh
001D1626 db ffh
001D1627 db ffh
001D1628 db 01h
001D1629 db 00h
001D162A db 00h
001D162B db 00h
001D162C db 30h
001D162D db 16h
001D162E db 1dh
001D162F db 00h
001D1630 db 6eh
001D1631 db 00h
001D1632 db 61h
001D1633 db 00h