LINUX.ORG.RU

[C++] Несколько глупых вопросов

 


0

1

Я тут вознамерился переписать парочку стандартных контейнеров джаст фо лулз и встретил некоторые непонятности

#include <cstring>
#include <string>
#include <vector>
#include <iostream>
#include <stdio.h>

int main() {
    std::cout << sizeof(std::string) << std::endl;
    std::string s0;
    std::cout << sizeof(s0.c_str()) << std::endl;
    std::cout << sizeof(std::vector<char>) << std::endl;

    std::string s1 = "";
    printf("%p\n", &s1[0]);
    printf("%ld\n", s1.capacity());
    char s2[] = "_lol ololololo";
    int s2_l = std::strlen(s2);
    for (int i = 0; i < s2_l; i++) {
        s1.push_back(s2[i]);
        printf("%p\n", &s1[0]);
        printf("%ld\n", s1.capacity());
    }

    printf("%ld, %ld\n", s1.max_size(), sizeof(s1.max_size()));

    std::string s3 ("ol\0lo", 5);
    std::cout << s3 << std::endl;

    //s1 += s2;
    //printf("%p\n", s1.c_str());
}

1) почему размер std::string равен размеру указателя (8 байт в 64-битной системе), вроде ж в нем должен храниться указатель на байты и размер строки или нет? (в строке могут быть нулевые символы, без размера никак; где бы глянуть сорцы gcc'шного std::string?...)

2) отчего вектор чаров аж 24 байта занимает? по логике вещей ему должно хватать указателя на то что хранит (в данном примере байты) и длина вектора

3) изменение размера контейнеров делается realloc'ом (какбы после добавления чего-то в конец указатель не всегда меняется) или хитрой манипуляцией с new/delete?

4) чтобы запихнуть в std::string нулевые символы приходится еще длину строки передавать, как ее программно считать? strlen же до первого нулевого определит

Ответ на: комментарий от dismal_faun

> 1) а где конкретнее оно?
Погрепай basic_string.

3) собственно вопрос был что там в кишках у resize, reserve, capacity ...

Посмотри же.

anonymous
()
Ответ на: комментарий от anonymous

ok.

по поводу нулевого байта интересная штука

int main() {
    char s[] = "ol\0lo";
}
% gcc -S -O0 t.c -o t.s
        .file   "t.c"
        .section        .rodata
.LC0:
        .string "ol"
        .string "lo"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    .LC0(%rip), %eax
        movl    %eax, -16(%rbp)
        movzwl  .LC0+4(%rip), %eax
        movw    %ax, -12(%rbp)
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (Gentoo 4.6.1-r1 p1.0, pie-0.4.5) 4.6.1"
        .section        .note.GNU-stack,"",@progbits

т.е. компилятор будет нулем рвать мне строки?

dismal_faun ★★
() автор топика
Ответ на: комментарий от dismal_faun
int main() {
    char s[] = "ol\0lo^";
    char *c = s;
    while (*c != '^') printf("%d\n", *c++);
}

Никуда твой нуль не исчез, это всего лишь соглашение, на которое компилятору наплевать.

anonymous
()

2. а capacity ?

3. нет, realloc не знает ничего про конструкторы/деструкторы, а vector может хранить не только pod

Reset ★★★★★
()

1) почему размер std::string равен размеру указателя (8 байт в 64-битной системе), вроде ж в нем должен храниться указатель на байты и размер строки или нет? (в строке могут быть нулевые символы, без размера никак; где бы глянуть сорцы gcc'шного std::string?...)

Указатель на структуру данных, которая содержит (предположительно) указатель на строку, ее длину и счетчик ссылок. Гугли implicit sharing.

4) чтобы запихнуть в std::string нулевые символы приходится еще длину строки передавать, как ее программно считать? strlen же до первого нулевого определит

Длина отдельно хранится, а не вычисляется из strlen.

Pavval ★★★★★
()
Ответ на: комментарий от Pavval

implicit sharing типа для copy on write нужно?

#include <string>
#include <iostream>
#include <stdio.h>

int main() {
    std::string str0("pysch");
    std::string str1 = str0;
    printf("%p, %p\n", str0.c_str(), str1.c_str());
    str0[1] = 'Y';
    printf("%p, %p\n", str0.c_str(), str1.c_str());
    std::cout << str0 << std::endl;
    std::cout << str1 << std::endl;
}
0x603028, 0x603028
0x603088, 0x603028
pYsch
pysch

dismal_faun ★★
() автор топика
Ответ на: комментарий от anonymous

Странно, мой man выдает

#include <cstdlib>
#include "myclass.h"

int main (int argc, char* argv[])
{
    const int size = 10;
    
    void *p = std::malloc(sizeof(MyClass) * size);
    MyClass *my = new(p) MyClass[size];

    // ...
    
    for (int i = 0; i < size; ++i)
        my[i].~MyClass();
    std::free(p);
}
mannaz
()
Ответ на: комментарий от dismal_faun

> implicit sharing типа для copy on write нужно?

Именно так. Хотя полноценный COW с оператором [ ] реализовать на C++03 нереально, тем не менее это лучше, чем тупое копирование для строк.

m0rph ★★★★★
()
Ответ на: комментарий от m0rph

> Хотя полноценный COW с оператором [ ] реализовать на C++03 нереально

Чисто практически вполне реально. В том же Qt, например, QString::operator[] возвращает QCharRef вместо ссылки на символ. Но если класс реализует copy-on-write семантику, то лучше всегда добавлять явные методы для const-доступа вроде at() и т.п.

mannaz
()
Ответ на: комментарий от dismal_faun

implicit sharing типа для copy on write нужно?

Да.

Pavval ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.